diff --git a/src/duckdb/extension/core_functions/function_list.cpp b/src/duckdb/extension/core_functions/function_list.cpp index 4987d2e3f..0f14a8113 100644 --- a/src/duckdb/extension/core_functions/function_list.cpp +++ b/src/duckdb/extension/core_functions/function_list.cpp @@ -196,6 +196,7 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION_SET(GenerateSeriesFun), DUCKDB_SCALAR_FUNCTION(GetBitFun), DUCKDB_SCALAR_FUNCTION(GetCurrentTimestampFun), + DUCKDB_SCALAR_FUNCTION(GetTypeFun), DUCKDB_SCALAR_FUNCTION_SET_ALIAS(GradeUpFun), DUCKDB_SCALAR_FUNCTION_SET(GreatestFun), DUCKDB_SCALAR_FUNCTION_SET(GreatestCommonDivisorFun), @@ -266,6 +267,7 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION_SET(MakeTimestampFun), DUCKDB_SCALAR_FUNCTION_SET(MakeTimestampMsFun), DUCKDB_SCALAR_FUNCTION_SET(MakeTimestampNsFun), + DUCKDB_SCALAR_FUNCTION(MakeTypeFun), DUCKDB_SCALAR_FUNCTION_SET(MapFun), DUCKDB_SCALAR_FUNCTION(MapConcatFun), DUCKDB_SCALAR_FUNCTION(MapEntriesFun), diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/generic_functions.hpp b/src/duckdb/extension/core_functions/include/core_functions/scalar/generic_functions.hpp index 36afd4537..f8642e689 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/generic_functions.hpp +++ b/src/duckdb/extension/core_functions/include/core_functions/scalar/generic_functions.hpp @@ -85,6 +85,26 @@ struct TypeOfFun { static ScalarFunction GetFunction(); }; +struct GetTypeFun { + static constexpr const char *Name = "get_type"; + static constexpr const char *Parameters = "expression"; + static constexpr const char *Description = "Returns the type of the result of the expression"; + static constexpr const char *Example = "get_type('abc')"; + static constexpr const char *Categories = ""; + + static ScalarFunction GetFunction(); +}; + +struct MakeTypeFun { + static constexpr const char *Name = "make_type"; + static constexpr const char *Parameters = "name,..."; + static constexpr const char *Description = "Construct a type from its name and optional parameters"; + static constexpr const char *Example = "make_type('DECIMAL', 10, 2)"; + static constexpr const char *Categories = ""; + + static ScalarFunction GetFunction(); +}; + struct CanCastImplicitlyFun { static constexpr const char *Name = "can_cast_implicitly"; static constexpr const char *Parameters = "source_type,target_type"; diff --git a/src/duckdb/extension/core_functions/lambda_functions.cpp b/src/duckdb/extension/core_functions/lambda_functions.cpp index 89356921c..cc626d51e 100644 --- a/src/duckdb/extension/core_functions/lambda_functions.cpp +++ b/src/duckdb/extension/core_functions/lambda_functions.cpp @@ -5,6 +5,7 @@ #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/planner/expression/bound_lambda_expression.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/scalar/date/date_trunc.cpp b/src/duckdb/extension/core_functions/scalar/date/date_trunc.cpp index f4df3a25a..787dc77fd 100644 --- a/src/duckdb/extension/core_functions/scalar/date/date_trunc.cpp +++ b/src/duckdb/extension/core_functions/scalar/date/date_trunc.cpp @@ -517,7 +517,8 @@ unique_ptr DateTruncStatistics(vector &child_sta auto result = NumericStats::CreateEmpty(min_value.type()); NumericStats::SetMin(result, min_value); NumericStats::SetMax(result, max_value); - result.CopyValidity(child_stats[0]); + + result.CombineValidity(child_stats[0], child_stats[1]); return result.ToUnique(); } diff --git a/src/duckdb/extension/core_functions/scalar/generic/type_functions.cpp b/src/duckdb/extension/core_functions/scalar/generic/type_functions.cpp new file mode 100644 index 000000000..813e93228 --- /dev/null +++ b/src/duckdb/extension/core_functions/scalar/generic/type_functions.cpp @@ -0,0 +1,130 @@ +#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/planner/expression/bound_constant_expression.hpp" +#include "duckdb/planner/expression/bound_function_expression.hpp" +#include "duckdb/parser/expression/constant_expression.hpp" +#include "duckdb/planner/binder.hpp" +#include "duckdb/parser/expression/type_expression.hpp" +#include "duckdb/execution/expression_executor.hpp" + +namespace duckdb { + +//---------------------------------------------------------------------------------------------------------------------- +// typeof function +//---------------------------------------------------------------------------------------------------------------------- + +static void TypeOfFunction(DataChunk &args, ExpressionState &state, Vector &result) { + Value v(args.data[0].GetType().ToString()); + result.Reference(v); +} + +static unique_ptr BindTypeOfFunctionExpression(FunctionBindExpressionInput &input) { + auto &return_type = input.children[0]->return_type; + if (return_type.id() == LogicalTypeId::UNKNOWN || return_type.id() == LogicalTypeId::SQLNULL) { + // parameter - unknown return type + return nullptr; + } + // emit a constant expression + return make_uniq(Value(return_type.ToString())); +} + +ScalarFunction TypeOfFun::GetFunction() { + auto fun = ScalarFunction({LogicalType::ANY}, LogicalType::VARCHAR, TypeOfFunction); + fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); + fun.SetBindExpressionCallback(BindTypeOfFunctionExpression); + return fun; +} + +//---------------------------------------------------------------------------------------------------------------------- +// get_type function +//---------------------------------------------------------------------------------------------------------------------- +// This is like "typeof", except returns LogicalType::TYPE instead of VARCHAR + +static void GetTypeFunction(DataChunk &args, ExpressionState &state, Vector &result) { + auto v = Value::TYPE(args.data[0].GetType()); + result.Reference(v); +} + +static unique_ptr BindGetTypeFunction(ClientContext &context, ScalarFunction &bound_function, + vector> &arguments) { + if (arguments[0]->HasParameter()) { + throw ParameterNotResolvedException(); + } + bound_function.arguments[0] = arguments[0]->return_type; + return nullptr; +} + +static unique_ptr BindGetTypeFunctionExpression(FunctionBindExpressionInput &input) { + auto &return_type = input.children[0]->return_type; + if (return_type.id() == LogicalTypeId::UNKNOWN || return_type.id() == LogicalTypeId::SQLNULL) { + // parameter - unknown return type + return nullptr; + } + // emit a constant expression + return make_uniq(Value::TYPE(return_type)); +} + +ScalarFunction GetTypeFun::GetFunction() { + auto fun = ScalarFunction({LogicalType::ANY}, LogicalType::TYPE(), GetTypeFunction, BindGetTypeFunction); + fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); + fun.SetBindExpressionCallback(BindGetTypeFunctionExpression); + return fun; +} + +//---------------------------------------------------------------------------------------------------------------------- +// make_type function +//---------------------------------------------------------------------------------------------------------------------- +static void MakeTypeFunction(DataChunk &args, ExpressionState &state, Vector &result) { + throw InvalidInputException("make_type function can only be used in constant expressions"); +} + +static unique_ptr BindMakeTypeFunctionExpression(FunctionBindExpressionInput &input) { + vector> args; + + // Evaluate all arguments to constant values + for (auto &child : input.children) { + string name = child->alias; + if (!child->IsFoldable()) { + throw BinderException("make_type function arguments must be constant expressions"); + } + auto val = ExpressionExecutor::EvaluateScalar(input.context, *child); + args.emplace_back(name, val); + } + + if (args.empty()) { + throw BinderException("make_type function requires at least one argument"); + } + + if (args.front().second.type() != LogicalType::VARCHAR) { + throw BinderException("make_type function first argument must be the type name as VARCHAR"); + } + + vector> type_args; + for (idx_t i = 1; i < args.size(); i++) { + auto &arg = args[i]; + auto result = make_uniq(arg.second); + result->SetAlias(arg.first); + + type_args.push_back(std::move(result)); + } + + auto type_name = args.front().second.GetValue(); + auto qualified_name = QualifiedName::Parse(type_name); + + auto unbound_type = LogicalType::UNBOUND(make_uniq(qualified_name.catalog, qualified_name.schema, + qualified_name.name, std::move(type_args))); + + // Bind the unbound type + auto binder = Binder::CreateBinder(input.context); + binder->BindLogicalType(unbound_type); + return make_uniq(Value::TYPE(unbound_type)); +} + +ScalarFunction MakeTypeFun::GetFunction() { + auto fun = ScalarFunction({LogicalType::VARCHAR}, LogicalType::TYPE(), MakeTypeFunction); + fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); + fun.SetBindExpressionCallback(BindMakeTypeFunctionExpression); + fun.varargs = LogicalType::ANY; + return fun; +} + +} // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/generic/typeof.cpp b/src/duckdb/extension/core_functions/scalar/generic/typeof.cpp deleted file mode 100644 index 008df7678..000000000 --- a/src/duckdb/extension/core_functions/scalar/generic/typeof.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "core_functions/scalar/generic_functions.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -namespace { - -void TypeOfFunction(DataChunk &args, ExpressionState &state, Vector &result) { - Value v(args.data[0].GetType().ToString()); - result.Reference(v); -} - -unique_ptr BindTypeOfFunctionExpression(FunctionBindExpressionInput &input) { - auto &return_type = input.children[0]->return_type; - if (return_type.id() == LogicalTypeId::UNKNOWN || return_type.id() == LogicalTypeId::SQLNULL) { - // parameter - unknown return type - return nullptr; - } - // emit a constant expression - return make_uniq(Value(return_type.ToString())); -} - -} // namespace - -ScalarFunction TypeOfFun::GetFunction() { - auto fun = ScalarFunction({LogicalType::ANY}, LogicalType::VARCHAR, TypeOfFunction); - fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); - fun.SetBindExpressionCallback(BindTypeOfFunctionExpression); - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/list/list_filter.cpp b/src/duckdb/extension/core_functions/scalar/list/list_filter.cpp index 017c611a2..69fd5c906 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_filter.cpp +++ b/src/duckdb/extension/core_functions/scalar/list/list_filter.cpp @@ -2,6 +2,7 @@ #include "duckdb/function/lambda_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/planner/expression/bound_lambda_expression.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/scalar/list/list_reduce.cpp b/src/duckdb/extension/core_functions/scalar/list/list_reduce.cpp index f3c23e98f..1960d64fc 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_reduce.cpp +++ b/src/duckdb/extension/core_functions/scalar/list/list_reduce.cpp @@ -1,6 +1,8 @@ #include "core_functions/scalar/list_functions.hpp" + #include "duckdb/function/lambda_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/planner/expression/bound_lambda_expression.hpp" namespace duckdb { @@ -46,6 +48,7 @@ struct ReduceExecuteInfo { } input_types.push_back(left_slice->GetType()); input_types.push_back(left_slice->GetType()); + // skip the first entry if there is an initial value for (idx_t i = info.has_initial ? 1 : 0; i < info.column_infos.size(); i++) { input_types.push_back(info.column_infos[i].vector.get().GetType()); diff --git a/src/duckdb/extension/core_functions/scalar/list/list_transform.cpp b/src/duckdb/extension/core_functions/scalar/list/list_transform.cpp index be4f319a9..c9aada10b 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_transform.cpp +++ b/src/duckdb/extension/core_functions/scalar/list/list_transform.cpp @@ -2,6 +2,7 @@ #include "duckdb/function/lambda_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/planner/expression/bound_lambda_expression.hpp" namespace duckdb { diff --git a/src/duckdb/extension/icu/icu-makedate.cpp b/src/duckdb/extension/icu/icu-makedate.cpp index 128e80d93..fb477122d 100644 --- a/src/duckdb/extension/icu/icu-makedate.cpp +++ b/src/duckdb/extension/icu/icu-makedate.cpp @@ -2,13 +2,12 @@ #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/operator/subtract.hpp" #include "duckdb/common/types/date.hpp" -#include "duckdb/common/types/time.hpp" #include "duckdb/common/types/timestamp.hpp" #include "duckdb/common/vector_operations/senary_executor.hpp" #include "duckdb/common/vector_operations/septenary_executor.hpp" #include "duckdb/function/cast/cast_function_set.hpp" #include "duckdb/main/extension/extension_loader.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" +#include "duckdb/main/settings.hpp" #include "include/icu-casts.hpp" #include "include/icu-datefunc.hpp" #include "include/icu-datetrunc.hpp" @@ -57,6 +56,10 @@ BoundCastInfo ICUMakeDate::BindCastToDate(BindCastInput &input, const LogicalTyp if (!input.context) { throw InternalException("Missing context for TIMESTAMPTZ to DATE cast."); } + if (Settings::Get(*input.context)) { + throw BinderException("Casting from TIMESTAMP WITH TIME ZONE to DATE without an explicit time zone " + "has been disabled - use \"AT TIME ZONE ...\""); + } auto cast_data = make_uniq(make_uniq(*input.context)); @@ -80,7 +83,7 @@ struct ICUMakeTimestampTZFunc : public ICUDateFunc { ss -= secs; ss *= Interval::MSECS_PER_SEC; const auto millis = int32_t(ss); - int64_t micros = std::round((ss - millis) * Interval::MICROS_PER_MSEC); + int64_t micros = LossyNumericCast(std::round((ss - millis) * Interval::MICROS_PER_MSEC)); calendar->set(UCAL_YEAR, year); calendar->set(UCAL_MONTH, month); diff --git a/src/duckdb/extension/icu/icu-timezone.cpp b/src/duckdb/extension/icu/icu-timezone.cpp index 65993beaf..d3925df39 100644 --- a/src/duckdb/extension/icu/icu-timezone.cpp +++ b/src/duckdb/extension/icu/icu-timezone.cpp @@ -164,7 +164,7 @@ struct ICUFromNaiveTimestamp : public ICUDateFunc { if (!input.context) { throw InternalException("Missing context for TIMESTAMP to TIMESTAMPTZ cast."); } - if (DBConfig::GetSetting(*input.context)) { + if (Settings::Get(*input.context)) { throw BinderException("Casting from TIMESTAMP to TIMESTAMP WITH TIME ZONE without an explicit time zone " "has been disabled - use \"AT TIME ZONE ...\""); } @@ -251,7 +251,7 @@ struct ICUToNaiveTimestamp : public ICUDateFunc { if (!input.context) { throw InternalException("Missing context for TIMESTAMPTZ to TIMESTAMP cast."); } - if (DBConfig::GetSetting(*input.context)) { + if (Settings::Get(*input.context)) { throw BinderException("Casting from TIMESTAMP WITH TIME ZONE to TIMESTAMP without an explicit time zone " "has been disabled - use \"AT TIME ZONE ...\""); } diff --git a/src/duckdb/extension/json/include/json_structure.hpp b/src/duckdb/extension/json/include/json_structure.hpp index 584069981..c0fee24ab 100644 --- a/src/duckdb/extension/json/include/json_structure.hpp +++ b/src/duckdb/extension/json/include/json_structure.hpp @@ -80,6 +80,9 @@ struct JSONStructureDescription { //! Candidate types (if auto-detecting and type == LogicalTypeId::VARCHAR) vector candidate_types; + + //! Whether any UBIGINT value exceeds the BIGINT range (i.e., >= 2^63) + bool has_large_ubigint = false; }; struct JSONStructure { diff --git a/src/duckdb/extension/json/json_functions/copy_json.cpp b/src/duckdb/extension/json/json_functions/copy_json.cpp index 17630e466..3470e2f68 100644 --- a/src/duckdb/extension/json/json_functions/copy_json.cpp +++ b/src/duckdb/extension/json/json_functions/copy_json.cpp @@ -55,6 +55,9 @@ static BoundStatement CopyToJSONPlan(Binder &binder, CopyStatement &stmt) { csv_copy_options["suffix"] = {"\n]\n"}; csv_copy_options["new_line"] = {",\n\t"}; } + } else if (loption == "file_extension") { + // Since we set the file extension to "json" above, we need to override it + csv_copy_options["file_extension"] = {StringValue::Get(kv.second.back())}; } else if (SUPPORTED_BASE_OPTIONS.find(loption) != SUPPORTED_BASE_OPTIONS.end()) { // We support these base options csv_copy_options.insert(kv); diff --git a/src/duckdb/extension/json/json_functions/json_create.cpp b/src/duckdb/extension/json/json_functions/json_create.cpp index d1c8a8afb..f7566002f 100644 --- a/src/duckdb/extension/json/json_functions/json_create.cpp +++ b/src/duckdb/extension/json/json_functions/json_create.cpp @@ -605,8 +605,9 @@ static void CreateValues(const StructNames &names, yyjson_mut_doc *doc, yyjson_m case LogicalTypeId::INVALID: case LogicalTypeId::UNKNOWN: case LogicalTypeId::ANY: - case LogicalTypeId::USER: case LogicalTypeId::TEMPLATE: + case LogicalTypeId::UNBOUND: + case LogicalTypeId::TYPE: case LogicalTypeId::VARIANT: case LogicalTypeId::CHAR: case LogicalTypeId::STRING_LITERAL: diff --git a/src/duckdb/extension/json/json_functions/json_structure.cpp b/src/duckdb/extension/json/json_functions/json_structure.cpp index 7dc46de55..8d0633a52 100644 --- a/src/duckdb/extension/json/json_functions/json_structure.cpp +++ b/src/duckdb/extension/json/json_functions/json_structure.cpp @@ -9,7 +9,8 @@ namespace duckdb { static bool IsNumeric(LogicalTypeId type) { - return type == LogicalTypeId::DOUBLE || type == LogicalTypeId::UBIGINT || type == LogicalTypeId::BIGINT; + return type == LogicalTypeId::DOUBLE || type == LogicalTypeId::UBIGINT || type == LogicalTypeId::BIGINT || + type == LogicalTypeId::HUGEINT; } static LogicalTypeId MaxNumericType(const LogicalTypeId &a, const LogicalTypeId &b) { @@ -17,6 +18,14 @@ static LogicalTypeId MaxNumericType(const LogicalTypeId &a, const LogicalTypeId if (a == LogicalTypeId::DOUBLE || b == LogicalTypeId::DOUBLE) { return LogicalTypeId::DOUBLE; } + if (a == LogicalTypeId::HUGEINT || b == LogicalTypeId::HUGEINT) { + return LogicalTypeId::HUGEINT; + } + // One is BIGINT and the other is UBIGINT - need HUGEINT to represent both ranges + if ((a == LogicalTypeId::BIGINT && b == LogicalTypeId::UBIGINT) || + (a == LogicalTypeId::UBIGINT && b == LogicalTypeId::BIGINT)) { + return LogicalTypeId::HUGEINT; + } return LogicalTypeId::BIGINT; } @@ -343,6 +352,7 @@ static void SwapJSONStructureDescription(JSONStructureDescription &a, JSONStruct std::swap(a.key_map, b.key_map); std::swap(a.children, b.children); std::swap(a.candidate_types, b.candidate_types); + std::swap(a.has_large_ubigint, b.has_large_ubigint); } JSONStructureDescription::JSONStructureDescription(JSONStructureDescription &&other) noexcept { @@ -427,7 +437,11 @@ static void ExtractStructureObject(yyjson_val *obj, JSONStructureNode &node, con static void ExtractStructureVal(yyjson_val *val, JSONStructureNode &node) { D_ASSERT(!yyjson_is_arr(val) && !yyjson_is_obj(val)); - node.GetOrCreateDescription(JSONCommon::ValTypeToLogicalTypeId(val)); + auto &desc = node.GetOrCreateDescription(JSONCommon::ValTypeToLogicalTypeId(val)); + if (desc.type == LogicalTypeId::UBIGINT && + unsafe_yyjson_get_uint(val) > static_cast(NumericLimits::Maximum())) { + desc.has_large_ubigint = true; + } } void JSONStructure::ExtractStructure(yyjson_val *val, JSONStructureNode &node, const bool ignore_errors) { @@ -558,6 +572,9 @@ static void MergeNodeVal(JSONStructureNode &merged, const JSONStructureDescripti const bool node_initialized) { D_ASSERT(child_desc.type != LogicalTypeId::LIST && child_desc.type != LogicalTypeId::STRUCT); auto &merged_desc = merged.GetOrCreateDescription(child_desc.type); + if (child_desc.has_large_ubigint) { + merged_desc.has_large_ubigint = true; + } if (merged_desc.type != LogicalTypeId::VARCHAR || !node_initialized || merged.descriptions.size() != 1) { return; } @@ -798,7 +815,10 @@ LogicalType JSONStructure::StructureToType(ClientContext &context, const JSONStr case LogicalTypeId::VARCHAR: return StructureToTypeString(node); case LogicalTypeId::UBIGINT: - return LogicalTypeId::BIGINT; // We prefer not to return UBIGINT in our type auto-detection + if (desc.has_large_ubigint) { + return LogicalTypeId::HUGEINT; + } + return LogicalTypeId::BIGINT; case LogicalTypeId::SQLNULL: return null_type; default: diff --git a/src/duckdb/extension/json/json_reader.cpp b/src/duckdb/extension/json/json_reader.cpp index 2b509a542..25feff588 100644 --- a/src/duckdb/extension/json/json_reader.cpp +++ b/src/duckdb/extension/json/json_reader.cpp @@ -1,10 +1,13 @@ #include "json_reader.hpp" +#include + #include "duckdb/common/file_opener.hpp" +#include "duckdb/common/file_open_flags.hpp" #include "duckdb/common/serializer/deserializer.hpp" #include "duckdb/common/serializer/serializer.hpp" +#include "duckdb/storage/caching_mode.hpp" #include "json_scan.hpp" -#include namespace duckdb { @@ -183,7 +186,9 @@ void JSONReader::OpenJSONFile() { lock_guard guard(lock); if (!IsOpen()) { auto &fs = FileSystem::GetFileSystem(context); - auto regular_file_handle = fs.OpenFile(file, FileFlags::FILE_FLAGS_READ | options.compression); + FileOpenFlags flags = FileFlags::FILE_FLAGS_READ | options.compression; + flags.SetCachingMode(CachingMode::CACHE_REMOTE_ONLY); + auto regular_file_handle = fs.OpenFile(file, flags); file_handle = make_uniq(context, std::move(regular_file_handle), BufferAllocator::Get(context)); } Reset(); @@ -1052,8 +1057,9 @@ void JSONReader::ReadNextBufferSeek(JSONReaderScanState &scan_state) { if (!raw_handle.OnDiskFile() && raw_handle.CanSeek()) { if (!scan_state.thread_local_filehandle || scan_state.thread_local_filehandle->GetPath() != raw_handle.GetPath()) { - scan_state.thread_local_filehandle = scan_state.fs.OpenFile( - raw_handle.GetPath(), FileFlags::FILE_FLAGS_READ | FileFlags::FILE_FLAGS_DIRECT_IO); + FileOpenFlags flags = FileFlags::FILE_FLAGS_READ | FileFlags::FILE_FLAGS_DIRECT_IO; + flags.SetCachingMode(CachingMode::CACHE_REMOTE_ONLY); + scan_state.thread_local_filehandle = scan_state.fs.OpenFile(raw_handle.GetPath(), flags); } } else if (scan_state.thread_local_filehandle) { scan_state.thread_local_filehandle = nullptr; diff --git a/src/duckdb/extension/parquet/column_writer.cpp b/src/duckdb/extension/parquet/column_writer.cpp index cf0652ede..8eda20e4f 100644 --- a/src/duckdb/extension/parquet/column_writer.cpp +++ b/src/duckdb/extension/parquet/column_writer.cpp @@ -288,6 +288,9 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont //! Construct the column schema auto variant_column = ParquetColumnSchema::FromLogicalType(name, type, max_define, max_repeat, 0, null_type, allow_geometry); + if (field_id && field_id->set) { + variant_column.field_id = field_id->field_id; + } vector> child_writers; child_writers.reserve(child_types.size()); diff --git a/src/duckdb/extension/parquet/include/column_writer.hpp b/src/duckdb/extension/parquet/include/column_writer.hpp index 1463137ad..fb4a0c91e 100644 --- a/src/duckdb/extension/parquet/include/column_writer.hpp +++ b/src/duckdb/extension/parquet/include/column_writer.hpp @@ -122,7 +122,7 @@ class ColumnWriter { } return false; } - virtual LogicalType TransformedType() { + virtual LogicalType TransformedType() const { throw NotImplementedException("Writer does not have a transformed type"); } virtual unique_ptr TransformExpression(unique_ptr expr) { @@ -145,7 +145,7 @@ class ColumnWriter { throw NotImplementedException("Writer doesn't require an AnalyzeSchemaFinalize pass"); } - virtual void FinalizeSchema(vector &schemas) = 0; + virtual idx_t FinalizeSchema(vector &schemas) = 0; //! Create the column writer for a specific type recursively static unique_ptr CreateWriterRecursive(ClientContext &context, ParquetWriter &writer, @@ -179,6 +179,18 @@ class ColumnWriter { virtual void Write(ColumnWriterState &state, Vector &vector, idx_t count) = 0; virtual void FinalizeWrite(ColumnWriterState &state) = 0; +public: + template + TARGET &Cast() { + DynamicCastCheck(this); + return reinterpret_cast(*this); + } + template + const TARGET &Cast() const { + D_ASSERT(dynamic_cast(this)); + return reinterpret_cast(*this); + } + protected: void HandleDefineLevels(ColumnWriterState &state, ColumnWriterState *parent, const ValidityMask &validity, const idx_t count, const uint16_t define_value, const uint16_t null_value) const; @@ -189,6 +201,8 @@ class ColumnWriter { public: ParquetWriter &writer; + //! The parent writer (if this is a nested field) + optional_ptr parent; ParquetColumnSchema column_schema; vector schema_path; bool can_have_nulls; diff --git a/src/duckdb/extension/parquet/include/parquet_geometry.hpp b/src/duckdb/extension/parquet/include/parquet_geometry.hpp index 8e7c3ca2a..09db147eb 100644 --- a/src/duckdb/extension/parquet/include/parquet_geometry.hpp +++ b/src/duckdb/extension/parquet/include/parquet_geometry.hpp @@ -85,14 +85,14 @@ class GeoParquetFileMetadata { public: explicit GeoParquetFileMetadata(GeoParquetVersion geo_parquet_version) : version(geo_parquet_version) { } - void AddGeoParquetStats(const string &column_name, const LogicalType &type, const GeometryStatsData &stats, - GeoParquetVersion version); + void AddGeoParquetStats(ClientContext &context, const string &column_name, const LogicalType &type, + const GeometryStatsData &stats, GeoParquetVersion version); void Write(duckdb_parquet::FileMetaData &file_meta_data); // Try to read GeoParquet metadata. Returns nullptr if not found, invalid or the required spatial extension is not // available. static unique_ptr TryRead(const duckdb_parquet::FileMetaData &file_meta_data, - const ClientContext &context); + ClientContext &context); const unordered_map &GetColumnMeta() const; optional_ptr GetColumnMeta(const string &column_name) const; diff --git a/src/duckdb/extension/parquet/include/parquet_reader.hpp b/src/duckdb/extension/parquet/include/parquet_reader.hpp index a82bf737d..098406b78 100644 --- a/src/duckdb/extension/parquet/include/parquet_reader.hpp +++ b/src/duckdb/extension/parquet/include/parquet_reader.hpp @@ -109,7 +109,6 @@ struct ParquetOptions { bool binary_as_string = false; bool file_row_number = false; shared_ptr encryption_config; - bool debug_use_openssl = true; vector schema; idx_t explicit_cardinality = 0; diff --git a/src/duckdb/extension/parquet/include/parquet_shredding.hpp b/src/duckdb/extension/parquet/include/parquet_shredding.hpp index f43cbc42c..9e4e5ebe5 100644 --- a/src/duckdb/extension/parquet/include/parquet_shredding.hpp +++ b/src/duckdb/extension/parquet/include/parquet_shredding.hpp @@ -36,7 +36,7 @@ struct ShreddingType { static ShreddingType Deserialize(Deserializer &source); public: - static ShreddingType GetShreddingTypes(const Value &val); + static ShreddingType GetShreddingTypes(const Value &val, ClientContext &context); void AddChild(const string &name, ShreddingType &&child); optional_ptr GetChild(const string &name) const; diff --git a/src/duckdb/extension/parquet/include/parquet_writer.hpp b/src/duckdb/extension/parquet/include/parquet_writer.hpp index f28b07bbe..f07d9264a 100644 --- a/src/duckdb/extension/parquet/include/parquet_writer.hpp +++ b/src/duckdb/extension/parquet/include/parquet_writer.hpp @@ -110,8 +110,8 @@ class ParquetWriter { ShreddingType shredding_types, const vector> &kv_metadata, shared_ptr encryption_config, optional_idx dictionary_size_limit, idx_t string_dictionary_page_size_limit, bool enable_bloom_filters, - double bloom_filter_false_positive_ratio, int64_t compression_level, bool debug_use_openssl, - ParquetVersion parquet_version, GeoParquetVersion geoparquet_version); + double bloom_filter_false_positive_ratio, int64_t compression_level, ParquetVersion parquet_version, + GeoParquetVersion geoparquet_version); ~ParquetWriter(); public: @@ -123,7 +123,7 @@ class ParquetWriter { static duckdb_parquet::Type::type DuckDBTypeToParquetType(const LogicalType &duckdb_type); static void SetSchemaProperties(const LogicalType &duckdb_type, duckdb_parquet::SchemaElement &schema_ele, - bool allow_geometry); + bool allow_geometry, ClientContext &context); ClientContext &GetContext() { return context; @@ -207,7 +207,6 @@ class ParquetWriter { bool enable_bloom_filters; double bloom_filter_false_positive_ratio; int64_t compression_level; - bool debug_use_openssl; shared_ptr encryption_util; ParquetVersion parquet_version; GeoParquetVersion geoparquet_version; diff --git a/src/duckdb/extension/parquet/include/reader/string_column_reader.hpp b/src/duckdb/extension/parquet/include/reader/string_column_reader.hpp index d40051616..e837ce092 100644 --- a/src/duckdb/extension/parquet/include/reader/string_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/reader/string_column_reader.hpp @@ -38,7 +38,7 @@ class StringColumnReader : public ColumnReader { public: static bool IsValid(const char *str_data, uint32_t str_len, bool is_varchar); static bool IsValid(const string &str, bool is_varchar); - static void VerifyString(const char *str_data, uint32_t str_len, bool is_varchar); + void VerifyString(const char *str_data, uint32_t str_len, bool is_varchar) const; void VerifyString(const char *str_data, uint32_t str_len) const; static void ReferenceBlock(Vector &result, shared_ptr &block); diff --git a/src/duckdb/extension/parquet/include/reader/variant_column_reader.hpp b/src/duckdb/extension/parquet/include/reader/variant_column_reader.hpp index 69b429626..ad3e8533d 100644 --- a/src/duckdb/extension/parquet/include/reader/variant_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/reader/variant_column_reader.hpp @@ -35,6 +35,7 @@ class VariantColumnReader : public ColumnReader { idx_t GroupRowsAvailable() override; uint64_t TotalCompressedSize() override; void RegisterPrefetch(ThriftFileTransport &transport, bool allow_merge) override; + static bool TypedValueLayoutToType(const LogicalType &typed_value, LogicalType &logical_type); protected: idx_t metadata_reader_idx; diff --git a/src/duckdb/extension/parquet/include/writer/list_column_writer.hpp b/src/duckdb/extension/parquet/include/writer/list_column_writer.hpp index df7ecf276..ba841ac4e 100644 --- a/src/duckdb/extension/parquet/include/writer/list_column_writer.hpp +++ b/src/duckdb/extension/parquet/include/writer/list_column_writer.hpp @@ -44,10 +44,11 @@ class ListColumnWriter : public ColumnWriter { void BeginWrite(ColumnWriterState &state) override; void Write(ColumnWriterState &state, Vector &vector, idx_t count) override; void FinalizeWrite(ColumnWriterState &state) override; - void FinalizeSchema(vector &schemas) override; + idx_t FinalizeSchema(vector &schemas) override; protected: ColumnWriter &GetChildWriter(); + const ColumnWriter &GetChildWriter() const; }; } // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/writer/parquet_write_operators.hpp b/src/duckdb/extension/parquet/include/writer/parquet_write_operators.hpp index 95bf21e2a..687f7afd7 100644 --- a/src/duckdb/extension/parquet/include/writer/parquet_write_operators.hpp +++ b/src/duckdb/extension/parquet/include/writer/parquet_write_operators.hpp @@ -237,11 +237,6 @@ struct ParquetIntervalOperator : public BaseParquetOperator { } }; -struct ParquetUUIDTargetType { - static constexpr const idx_t PARQUET_UUID_SIZE = 16; - data_t bytes[PARQUET_UUID_SIZE]; -}; - struct ParquetUUIDOperator : public BaseParquetOperator { template static TGT Operation(SRC input) { @@ -274,11 +269,13 @@ struct ParquetUUIDOperator : public BaseParquetOperator { template static void HandleStats(ColumnWriterStatistics *stats_p, TGT target_value) { auto &stats = stats_p->Cast(); - if (!stats.has_stats || memcmp(target_value.bytes, stats.min, ParquetUUIDTargetType::PARQUET_UUID_SIZE) < 0) { - memcpy(stats.min, target_value.bytes, ParquetUUIDTargetType::PARQUET_UUID_SIZE); + if (!stats.has_stats || + memcmp(target_value.bytes, stats.min.bytes, ParquetUUIDTargetType::PARQUET_UUID_SIZE) < 0) { + stats.min = target_value; } - if (!stats.has_stats || memcmp(target_value.bytes, stats.max, ParquetUUIDTargetType::PARQUET_UUID_SIZE) > 0) { - memcpy(stats.max, target_value.bytes, ParquetUUIDTargetType::PARQUET_UUID_SIZE); + if (!stats.has_stats || + memcmp(target_value.bytes, stats.max.bytes, ParquetUUIDTargetType::PARQUET_UUID_SIZE) > 0) { + stats.max = target_value; } stats.has_stats = true; } diff --git a/src/duckdb/extension/parquet/include/writer/parquet_write_stats.hpp b/src/duckdb/extension/parquet/include/writer/parquet_write_stats.hpp index 840830e3a..dc42ce211 100644 --- a/src/duckdb/extension/parquet/include/writer/parquet_write_stats.hpp +++ b/src/duckdb/extension/parquet/include/writer/parquet_write_stats.hpp @@ -227,11 +227,16 @@ class StringStatisticsState : public ColumnWriterStatistics { } }; +struct ParquetUUIDTargetType { + static constexpr const idx_t PARQUET_UUID_SIZE = 16; + data_t bytes[PARQUET_UUID_SIZE]; +}; + class UUIDStatisticsState : public ColumnWriterStatistics { public: bool has_stats = false; - data_t min[16] = {0}; - data_t max[16] = {0}; + ParquetUUIDTargetType min; + ParquetUUIDTargetType max; public: bool HasStats() override { @@ -245,10 +250,10 @@ class UUIDStatisticsState : public ColumnWriterStatistics { return GetMaxValue(); } string GetMinValue() override { - return HasStats() ? string(char_ptr_cast(min), 16) : string(); + return HasStats() ? string(char_ptr_cast(min.bytes), ParquetUUIDTargetType::PARQUET_UUID_SIZE) : string(); } string GetMaxValue() override { - return HasStats() ? string(char_ptr_cast(max), 16) : string(); + return HasStats() ? string(char_ptr_cast(max.bytes), ParquetUUIDTargetType::PARQUET_UUID_SIZE) : string(); } }; diff --git a/src/duckdb/extension/parquet/include/writer/primitive_column_writer.hpp b/src/duckdb/extension/parquet/include/writer/primitive_column_writer.hpp index 36874cf6d..3b3dd5dbe 100644 --- a/src/duckdb/extension/parquet/include/writer/primitive_column_writer.hpp +++ b/src/duckdb/extension/parquet/include/writer/primitive_column_writer.hpp @@ -74,7 +74,7 @@ class PrimitiveColumnWriter : public ColumnWriter { void BeginWrite(ColumnWriterState &state) override; void Write(ColumnWriterState &state, Vector &vector, idx_t count) override; void FinalizeWrite(ColumnWriterState &state) override; - void FinalizeSchema(vector &schemas) override; + idx_t FinalizeSchema(vector &schemas) override; protected: static void WriteLevels(Allocator &allocator, WriteStream &temp_writer, const unsafe_vector &levels, diff --git a/src/duckdb/extension/parquet/include/writer/struct_column_writer.hpp b/src/duckdb/extension/parquet/include/writer/struct_column_writer.hpp index a3d433467..f0dc047bd 100644 --- a/src/duckdb/extension/parquet/include/writer/struct_column_writer.hpp +++ b/src/duckdb/extension/parquet/include/writer/struct_column_writer.hpp @@ -18,6 +18,9 @@ class StructColumnWriter : public ColumnWriter { vector> child_writers_p) : ColumnWriter(writer, std::move(column_schema), std::move(schema_path_p)) { child_writers = std::move(child_writers_p); + for (auto &writer : child_writers) { + writer->parent = *this; + } } ~StructColumnWriter() override = default; @@ -32,7 +35,7 @@ class StructColumnWriter : public ColumnWriter { void BeginWrite(ColumnWriterState &state) override; void Write(ColumnWriterState &state, Vector &vector, idx_t count) override; void FinalizeWrite(ColumnWriterState &state) override; - void FinalizeSchema(vector &schemas) override; + idx_t FinalizeSchema(vector &schemas) override; }; } // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/writer/variant_column_writer.hpp b/src/duckdb/extension/parquet/include/writer/variant_column_writer.hpp index 07250c4ac..0f5f8424a 100644 --- a/src/duckdb/extension/parquet/include/writer/variant_column_writer.hpp +++ b/src/duckdb/extension/parquet/include/writer/variant_column_writer.hpp @@ -28,8 +28,12 @@ struct VariantAnalyzeData { public: //! Map for every value what type it is variant_type_map type_map = {}; + uint32_t decimal_width; + uint32_t decimal_scale; + bool decimal_consistent = false; + idx_t total_count = 0; + //! Map for every decimal value what physical type it has - array decimal_type_map = {}; unique_ptr object_data = nullptr; unique_ptr array_data = nullptr; }; @@ -72,7 +76,7 @@ class VariantColumnWriter : public StructColumnWriter { ~VariantColumnWriter() override = default; public: - void FinalizeSchema(vector &schemas) override; + idx_t FinalizeSchema(vector &schemas) override; unique_ptr AnalyzeSchemaInit() override; void AnalyzeSchema(ParquetAnalyzeSchemaState &state, Vector &input, idx_t count) override; void AnalyzeSchemaFinalize(const ParquetAnalyzeSchemaState &state) override; @@ -80,7 +84,7 @@ class VariantColumnWriter : public StructColumnWriter { bool HasTransform() override { return true; } - LogicalType TransformedType() override { + LogicalType TransformedType() const override { child_list_t children; for (auto &writer : child_writers) { auto &child_name = writer->Schema().name; diff --git a/src/duckdb/extension/parquet/parquet_crypto.cpp b/src/duckdb/extension/parquet/parquet_crypto.cpp index 7adba1cdf..6f00f28f6 100644 --- a/src/duckdb/extension/parquet/parquet_crypto.cpp +++ b/src/duckdb/extension/parquet/parquet_crypto.cpp @@ -163,8 +163,11 @@ class EncryptionTransport : public TTransport { public: EncryptionTransport(TProtocol &prot_p, const string &key, const EncryptionUtil &encryption_util_p) : prot(prot_p), trans(*prot.getTransport()), - aes(encryption_util_p.CreateEncryptionState(EncryptionTypes::GCM, key.size())), allocator(Allocator::DefaultAllocator(), ParquetCrypto::CRYPTO_BLOCK_SIZE) { + auto metadata = make_uniq(EncryptionTypes::GCM, key.size(), + EncryptionTypes::EncryptionVersion::NONE); + aes = encryption_util_p.CreateEncryptionState(std::move(metadata)); + Initialize(key); } @@ -190,8 +193,8 @@ class EncryptionTransport : public TTransport { const uint32_t total_length = ParquetCrypto::NONCE_BYTES + ciphertext_length + ParquetCrypto::TAG_BYTES; trans.write(const_data_ptr_cast(&total_length), ParquetCrypto::LENGTH_BYTES); - // Write nonce at beginning of encrypted chunk - trans.write(nonce, ParquetCrypto::NONCE_BYTES); + // Write nonce at the start of encrypted chunk + trans.write(nonce.data(), ParquetCrypto::NONCE_BYTES); data_t aes_buffer[ParquetCrypto::CRYPTO_BLOCK_SIZE]; auto current = allocator.GetTail(); @@ -220,10 +223,9 @@ class EncryptionTransport : public TTransport { private: void Initialize(const string &key) { // Generate Nonce - aes->GenerateRandomData(nonce, ParquetCrypto::NONCE_BYTES); + aes->GenerateRandomData(nonce.data(), nonce.size()); // Initialize Encryption - aes->InitializeEncryption(nonce, ParquetCrypto::NONCE_BYTES, reinterpret_cast(key.data()), - key.size()); + aes->InitializeEncryption(nonce, reinterpret_cast(key.data())); } private: @@ -235,7 +237,7 @@ class EncryptionTransport : public TTransport { shared_ptr aes; //! Nonce created by Initialize() - data_t nonce[ParquetCrypto::NONCE_BYTES]; + EncryptionNonce nonce; //! Arena Allocator to fully materialize in memory before encrypting ArenaAllocator allocator; @@ -246,9 +248,10 @@ class DecryptionTransport : public TTransport { public: DecryptionTransport(TProtocol &prot_p, const string &key, const EncryptionUtil &encryption_util_p, const CryptoMetaData &crypto_meta_data) - : prot(prot_p), trans(*prot.getTransport()), - aes(encryption_util_p.CreateEncryptionState(EncryptionTypes::GCM, key.size())), read_buffer_size(0), - read_buffer_offset(0) { + : prot(prot_p), trans(*prot.getTransport()), read_buffer_size(0), read_buffer_offset(0) { + auto metadata = make_uniq(EncryptionTypes::GCM, key.size(), + EncryptionTypes::EncryptionVersion::NONE); + aes = encryption_util_p.CreateEncryptionState(std::move(metadata)); Initialize(key, crypto_meta_data); } @@ -306,16 +309,15 @@ class DecryptionTransport : public TTransport { total_bytes = Load(length_buf); transport_remaining = total_bytes; // Read nonce and initialize AES - transport_remaining -= trans.read(nonce, ParquetCrypto::NONCE_BYTES); + transport_remaining -= trans.read(nonce.data(), nonce.total_size()); // check whether context is initialized if (!crypto_meta_data.IsEmpty()) { - aes->InitializeDecryption(nonce, ParquetCrypto::NONCE_BYTES, reinterpret_cast(key.data()), - key.size(), crypto_meta_data.additional_authenticated_data->data(), + aes->InitializeDecryption(nonce, reinterpret_cast(key.data()), + crypto_meta_data.additional_authenticated_data->data(), crypto_meta_data.additional_authenticated_data->size()); crypto_meta_data.additional_authenticated_data->Rewind(); } else { - aes->InitializeDecryption(nonce, ParquetCrypto::NONCE_BYTES, reinterpret_cast(key.data()), - key.size()); + aes->InitializeDecryption(nonce, reinterpret_cast(key.data())); } } @@ -353,7 +355,7 @@ class DecryptionTransport : public TTransport { uint32_t total_bytes; uint32_t transport_remaining; //! Nonce read by Initialize() - data_t nonce[ParquetCrypto::NONCE_BYTES]; + EncryptionNonce nonce; }; class SimpleReadTransport : public TTransport { diff --git a/src/duckdb/extension/parquet/parquet_extension.cpp b/src/duckdb/extension/parquet/parquet_extension.cpp index 59102a8eb..5f6944470 100644 --- a/src/duckdb/extension/parquet/parquet_extension.cpp +++ b/src/duckdb/extension/parquet/parquet_extension.cpp @@ -67,9 +67,8 @@ struct ParquetWriteBindData : public TableFunctionData { idx_t row_group_size = DEFAULT_ROW_GROUP_SIZE; idx_t row_group_size_bytes = NumericLimits::Maximum(); - //! How/Whether to encrypt the data + //! Encryption configuration shared_ptr encryption_config; - bool debug_use_openssl = true; //! After how many distinct values should we abandon dictionary compression and bloom filters? //! Defaults to 1/5th of the row group size if unset (in templated_column_writer.hpp) @@ -131,8 +130,8 @@ static void ParquetListCopyOptions(ClientContext &context, CopyOptionsInput &inp copy_options["dictionary_size_limit"] = CopyOption(LogicalType::BIGINT, CopyOptionMode::WRITE_ONLY); copy_options["string_dictionary_page_size_limit"] = CopyOption(LogicalType::UBIGINT, CopyOptionMode::WRITE_ONLY); copy_options["bloom_filter_false_positive_ratio"] = CopyOption(LogicalType::DOUBLE, CopyOptionMode::WRITE_ONLY); - copy_options["write_bloom_filter"] = CopyOption(LogicalType::BOOLEAN, CopyOptionMode::WRITE_ONLY); copy_options["debug_use_openssl"] = CopyOption(LogicalType::BOOLEAN, CopyOptionMode::READ_WRITE); + copy_options["write_bloom_filter"] = CopyOption(LogicalType::BOOLEAN, CopyOptionMode::WRITE_ONLY); copy_options["compression_level"] = CopyOption(LogicalType::BIGINT, CopyOptionMode::WRITE_ONLY); copy_options["parquet_version"] = CopyOption(LogicalType::VARCHAR, CopyOptionMode::WRITE_ONLY); copy_options["binary_as_string"] = CopyOption(LogicalType::BOOLEAN, CopyOptionMode::READ_ONLY); @@ -248,7 +247,8 @@ static unique_ptr ParquetWriteBind(ClientContext &context, CopyFun } } const auto &child_value = struct_children[i]; - bind_data->shredding_types.AddChild(col_name, ShreddingType::GetShreddingTypes(child_value)); + bind_data->shredding_types.AddChild(col_name, + ShreddingType::GetShreddingTypes(child_value, context)); } } } else if (loption == "kv_metadata") { @@ -271,7 +271,7 @@ static unique_ptr ParquetWriteBind(ClientContext &context, CopyFun } } else if (loption == "encryption_config") { bind_data->encryption_config = ParquetEncryptionConfig::Create(context, option.second[0]); - } else if (loption == "dictionary_compression_ratio_threshold") { + } else if (loption == "dictionary_compression_ratio_threshold" || loption == "debug_use_openssl") { // deprecated, ignore setting } else if (loption == "dictionary_size_limit") { auto val = option.second[0].GetValue(); @@ -295,15 +295,6 @@ static unique_ptr ParquetWriteBind(ClientContext &context, CopyFun throw BinderException("bloom_filter_false_positive_ratio must be greater than 0"); } bind_data->bloom_filter_false_positive_ratio = val; - } else if (loption == "debug_use_openssl") { - auto val = StringUtil::Lower(option.second[0].GetValue()); - if (val == "false") { - bind_data->debug_use_openssl = false; - } else if (val == "true") { - bind_data->debug_use_openssl = true; - } else { - throw BinderException("Expected debug_use_openssl to be a BOOLEAN"); - } } else if (loption == "compression_level") { const auto val = option.second[0].GetValue(); if (val < ZStdFileSystem::MinimumCompressionLevel() || val > ZStdFileSystem::MaximumCompressionLevel()) { @@ -340,7 +331,7 @@ static unique_ptr ParquetWriteBind(ClientContext &context, CopyFun } } if (row_group_size_bytes_set) { - if (DBConfig::GetSetting(context)) { + if (Settings::Get(context)) { throw BinderException("ROW_GROUP_SIZE_BYTES does not work while preserving insertion order. Use \"SET " "preserve_insertion_order=false;\" to disable preserving insertion order."); } @@ -366,8 +357,8 @@ static unique_ptr ParquetWriteInitializeGlobal(ClientContext parquet_bind.field_ids.Copy(), parquet_bind.shredding_types.Copy(), parquet_bind.kv_metadata, parquet_bind.encryption_config, parquet_bind.dictionary_size_limit, parquet_bind.string_dictionary_page_size_limit, parquet_bind.enable_bloom_filters, - parquet_bind.bloom_filter_false_positive_ratio, parquet_bind.compression_level, parquet_bind.debug_use_openssl, - parquet_bind.parquet_version, parquet_bind.geoparquet_version); + parquet_bind.bloom_filter_false_positive_ratio, parquet_bind.compression_level, parquet_bind.parquet_version, + parquet_bind.geoparquet_version); return std::move(global_state); } @@ -610,8 +601,6 @@ static void ParquetCopySerialize(Serializer &serializer, const FunctionData &bin serializer.WritePropertyWithDefault(109, "compression_level", compression_level); serializer.WritePropertyWithDefault(110, "row_groups_per_file", bind_data.row_groups_per_file, default_value.row_groups_per_file); - serializer.WritePropertyWithDefault(111, "debug_use_openssl", bind_data.debug_use_openssl, - default_value.debug_use_openssl); serializer.WritePropertyWithDefault(112, "dictionary_size_limit", bind_data.dictionary_size_limit, default_value.dictionary_size_limit); serializer.WritePropertyWithDefault(113, "bloom_filter_false_positive_ratio", @@ -647,8 +636,7 @@ static unique_ptr ParquetCopyDeserialize(Deserializer &deserialize ParquetWriteBindData default_value; data->row_groups_per_file = deserializer.ReadPropertyWithExplicitDefault( 110, "row_groups_per_file", default_value.row_groups_per_file); - data->debug_use_openssl = - deserializer.ReadPropertyWithExplicitDefault(111, "debug_use_openssl", default_value.debug_use_openssl); + deserializer.ReadDeletedProperty(111, "debug_use_openssl"); data->dictionary_size_limit = deserializer.ReadPropertyWithExplicitDefault(112, "dictionary_size_limit", optional_idx()); data->bloom_filter_false_positive_ratio = deserializer.ReadPropertyWithExplicitDefault( diff --git a/src/duckdb/extension/parquet/parquet_geometry.cpp b/src/duckdb/extension/parquet/parquet_geometry.cpp index fcbf13026..a3726a7ca 100644 --- a/src/duckdb/extension/parquet/parquet_geometry.cpp +++ b/src/duckdb/extension/parquet/parquet_geometry.cpp @@ -14,6 +14,7 @@ #include "yyjson.hpp" #include "duckdb/common/types/geometry_crs.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "re2/re2.h" #include "reader/string_column_reader.hpp" namespace duckdb { @@ -23,114 +24,8 @@ using namespace duckdb_yyjson; // NOLINT //------------------------------------------------------------------------------ // GeoParquetFileMetadata //------------------------------------------------------------------------------ -static constexpr auto OGC_CRS84_PROJJSON = R"JSON_LITERAL({ - "$schema": "https://proj.org/schemas/v0.7/projjson.schema.json", - "type": "GeographicCRS", - "name": "WGS 84 (CRS84)", - "datum_ensemble": { - "name": "World Geodetic System 1984 ensemble", - "members": [ - { - "name": "World Geodetic System 1984 (Transit)", - "id": { - "authority": "EPSG", - "code": 1166 - } - }, - { - "name": "World Geodetic System 1984 (G730)", - "id": { - "authority": "EPSG", - "code": 1152 - } - }, - { - "name": "World Geodetic System 1984 (G873)", - "id": { - "authority": "EPSG", - "code": 1153 - } - }, - { - "name": "World Geodetic System 1984 (G1150)", - "id": { - "authority": "EPSG", - "code": 1154 - } - }, - { - "name": "World Geodetic System 1984 (G1674)", - "id": { - "authority": "EPSG", - "code": 1155 - } - }, - { - "name": "World Geodetic System 1984 (G1762)", - "id": { - "authority": "EPSG", - "code": 1156 - } - }, - { - "name": "World Geodetic System 1984 (G2139)", - "id": { - "authority": "EPSG", - "code": 1309 - } - }, - { - "name": "World Geodetic System 1984 (G2296)", - "id": { - "authority": "EPSG", - "code": 1383 - } - } - ], - "ellipsoid": { - "name": "WGS 84", - "semi_major_axis": 6378137, - "inverse_flattening": 298.257223563 - }, - "accuracy": "2.0", - "id": { - "authority": "EPSG", - "code": 6326 - } - }, - "coordinate_system": { - "subtype": "ellipsoidal", - "axis": [ - { - "name": "Geodetic longitude", - "abbreviation": "Lon", - "direction": "east", - "unit": "degree" - }, - { - "name": "Geodetic latitude", - "abbreviation": "Lat", - "direction": "north", - "unit": "degree" - } - ] - }, - "scope": "Not known.", - "area": "World.", - "bbox": { - "south_latitude": -90, - "west_longitude": -180, - "north_latitude": 90, - "east_longitude": 180 - }, - "id": { - "authority": "OGC", - "code": "CRS84" - } -})JSON_LITERAL"; - unique_ptr GeoParquetFileMetadata::TryRead(const duckdb_parquet::FileMetaData &file_meta_data, - const ClientContext &context) { + ClientContext &context) { // Conversion not enabled, or spatial is not loaded! if (!IsGeoParquetConversionEnabled(context)) { return nullptr; @@ -233,7 +128,11 @@ unique_ptr GeoParquetFileMetadata::TryRead(const duckdb_ free(crs_json); } else { // Otherwise, default to OGC:CRS84 - column.projjson = OGC_CRS84_PROJJSON; + auto crs = CoordinateReferenceSystem::TryConvert(context, "OGC:CRS84", + CoordinateReferenceSystemType::PROJJSON); + if (crs) { + column.projjson = crs->GetDefinition(); + } } // TODO: Parse the bounding box, other metadata that might be useful. @@ -255,8 +154,41 @@ unique_ptr GeoParquetFileMetadata::TryRead(const duckdb_ return nullptr; } -void GeoParquetFileMetadata::AddGeoParquetStats(const string &column_name, const LogicalType &type, - const GeometryStatsData &stats, GeoParquetVersion version) { +static void ConvertCRS(ClientContext &context, GeoParquetColumnMetadata &column, const string &column_name, + const CoordinateReferenceSystem &crs, GeoParquetVersion version) { + // This is the default in GeoParquet + if (StringUtil::CIEquals("OGC:CRS84", crs.GetIdentifier())) { + // Dont write the default + return; + } + + if (crs.GetType() == CoordinateReferenceSystemType::PROJJSON) { + // If already PROJJSON, just write it directly + column.projjson = crs.GetDefinition(); + return; + } + + const auto lookup = CoordinateReferenceSystem::TryConvert(context, crs, CoordinateReferenceSystemType::PROJJSON); + + if (lookup) { + // Successfully converted to PROJJSON + column.projjson = lookup->GetDefinition(); + return; + } + + if (version != GeoParquetVersion::V2) { + throw InvalidInputException("Cannot write GeoParquet V1 metadata for column '%s': GeoParquet V1 only " + "supports PROJJSON CRS definitions", + column_name); + } + + // Fall back to writing the original CRS definition + column.projjson = crs.GetDefinition(); +} + +void GeoParquetFileMetadata::AddGeoParquetStats(ClientContext &context, const string &column_name, + const LogicalType &type, const GeometryStatsData &stats, + GeoParquetVersion version) { // Lock the metadata lock_guard glock(write_lock); @@ -267,25 +199,13 @@ void GeoParquetFileMetadata::AddGeoParquetStats(const string &column_name, const // Attempt to convert the CRS to PROJJSON if (GeoType::HasCRS(type)) { - const auto &crs = GeoType::GetCRS(type); - - // OGC:CRS84 is the default if no CRS is specified in GeoParquet, so we can skip writing it out if set - if (!StringUtil::CIEquals(crs.GetCode(), "OGC:CRS84")) { - // Only PROJJSON is supported in GeoParquet V1 - if (version != GeoParquetVersion::V2 && crs.GetType() != CoordinateReferenceSystemType::PROJJSON) { - // TODO: Try to convert other CRS types to equivalent PROJJSON - throw InvalidInputException("Cannot write GeoParquet V1 metadata for column '%s': GeoParquet only " - "supports PROJJSON CRS definitions", - column_name); - } - - column.projjson = crs.GetDefinition(); - } + ConvertCRS(context, column, column_name, GeoType::GetCRS(type), version); } // Merge the stats column.stats.Merge(stats); column.insertion_index = geometry_columns.size() - 1; + } else { it->second.stats.Merge(stats); } diff --git a/src/duckdb/extension/parquet/parquet_multi_file_info.cpp b/src/duckdb/extension/parquet/parquet_multi_file_info.cpp index fae40a9d6..f3120eed9 100644 --- a/src/duckdb/extension/parquet/parquet_multi_file_info.cpp +++ b/src/duckdb/extension/parquet/parquet_multi_file_info.cpp @@ -360,8 +360,7 @@ bool ParquetMultiFileInfo::ParseCopyOption(ClientContext &context, const string return true; } if (key == "debug_use_openssl") { - options.debug_use_openssl = GetBooleanArgument(key, values); - return true; + return true; // deprecated } if (key == "encryption_config") { if (values.size() != 1) { @@ -402,8 +401,7 @@ bool ParquetMultiFileInfo::ParseOption(ClientContext &context, const string &ori return true; } if (key == "debug_use_openssl") { - options.debug_use_openssl = BooleanValue::Get(val); - return true; + return true; // deprecated } if (key == "can_have_nan") { options.can_have_nan = BooleanValue::Get(val); @@ -455,7 +453,6 @@ void ParquetMultiFileInfo::GetBindInfo(const TableFunctionData &bind_data_p, Bin info.type = ScanType::PARQUET; info.InsertOption("binary_as_string", Value::BOOLEAN(parquet_options.binary_as_string)); info.InsertOption("file_row_number", Value::BOOLEAN(parquet_options.file_row_number)); - info.InsertOption("debug_use_openssl", Value::BOOLEAN(parquet_options.debug_use_openssl)); } optional_idx ParquetMultiFileInfo::MaxThreads(const MultiFileBindData &bind_data_p, diff --git a/src/duckdb/extension/parquet/parquet_reader.cpp b/src/duckdb/extension/parquet/parquet_reader.cpp index 8f4cd3997..05a02719a 100644 --- a/src/duckdb/extension/parquet/parquet_reader.cpp +++ b/src/duckdb/extension/parquet/parquet_reader.cpp @@ -25,6 +25,7 @@ #include "duckdb/optimizer/statistics_propagator.hpp" #include "duckdb/planner/table_filter_state.hpp" #include "duckdb/common/multi_file/multi_file_reader.hpp" +#include "duckdb/common/types/geometry_crs.hpp" namespace duckdb { @@ -552,13 +553,23 @@ ParquetColumnSchema ParquetReader::ParseSchemaRecursive(idx_t depth, idx_t max_d // which performs the WKB validation/transformation using the `ST_GeomFromWKB` function of DuckDB. // This enables us to also support other geometry encodings (such as GeoArrow geometries) easier in the future. + // Try to parse the CRS + LogicalType target_type; + + auto lookup = CoordinateReferenceSystem::TryIdentify(context, crs); + if (lookup) { + target_type = LogicalType::GEOMETRY(*lookup); + } else { + target_type = LogicalType::GEOMETRY(); + } + // Inner BLOB schema vector geometry_child; geometry_child.emplace_back(ParseColumnSchema(s_ele, max_define, max_repeat, this_idx, next_file_idx)); // Wrap in geometry schema - return ParquetColumnSchema::FromChildSchemas(s_ele.name, LogicalType::GEOMETRY(crs), max_define, max_repeat, - this_idx, next_file_idx++, std::move(geometry_child), + return ParquetColumnSchema::FromChildSchemas(s_ele.name, target_type, max_define, max_repeat, this_idx, + next_file_idx++, std::move(geometry_child), ParquetColumnSchemaType::GEOMETRY); } @@ -786,7 +797,7 @@ ParquetColumnDefinition ParquetColumnDefinition::FromSchemaValue(ClientContext & const auto children = StructValue::GetChildren(column_def); result.name = StringValue::Get(children[0]); - result.type = TransformStringToLogicalType(StringValue::Get(children[1])); + result.type = TransformStringToLogicalType(StringValue::Get(children[1]), context); string error_message; if (!children[2].TryCastAs(context, result.type, result.default_value, &error_message)) { throw BinderException("Unable to cast Parquet schema default_value \"%s\" to %s", children[2].ToString(), @@ -821,13 +832,11 @@ ParquetReader::ParquetReader(ClientContext &context_p, OpenFileInfo file_p, Parq footer_size = UBigIntValue::Get(footer_entry->second); } } - // set pointer to factory method for AES state - auto &config = DBConfig::GetConfig(context_p); - if (config.encryption_util && parquet_options.debug_use_openssl) { - encryption_util = config.encryption_util; - } else { - encryption_util = make_shared_ptr(); - } + + // Get the encryption util + // The parquet reader only reads data, so we set util to true + encryption_util = context_p.db->GetEncryptionUtil(true); + // If metadata cached is disabled // or if this file has cached metadata // or if the cached version already expired diff --git a/src/duckdb/extension/parquet/parquet_shredding.cpp b/src/duckdb/extension/parquet/parquet_shredding.cpp index b7ed673a8..c5f5092ea 100644 --- a/src/duckdb/extension/parquet/parquet_shredding.cpp +++ b/src/duckdb/extension/parquet/parquet_shredding.cpp @@ -68,12 +68,12 @@ optional_ptr ShreddingType::GetChild(const string &name) co return it->second; } -ShreddingType ShreddingType::GetShreddingTypes(const Value &val) { +ShreddingType ShreddingType::GetShreddingTypes(const Value &val, ClientContext &context) { if (val.type().id() != LogicalTypeId::VARCHAR) { throw BinderException("SHREDDING value should be of type VARCHAR, a stringified type to use for the column"); } auto type_str = val.GetValue(); - auto logical_type = TransformStringToLogicalType(type_str); + auto logical_type = TransformStringToLogicalType(type_str, context); return ConvertShreddingTypeRecursive(logical_type); } diff --git a/src/duckdb/extension/parquet/parquet_statistics.cpp b/src/duckdb/extension/parquet/parquet_statistics.cpp index 33a52abf1..d72969795 100644 --- a/src/duckdb/extension/parquet/parquet_statistics.cpp +++ b/src/duckdb/extension/parquet/parquet_statistics.cpp @@ -7,13 +7,16 @@ #include "parquet_reader.hpp" #include "reader/string_column_reader.hpp" #include "reader/struct_column_reader.hpp" +#include "reader/variant_column_reader.hpp" #include "zstd/common/xxhash.hpp" #include "duckdb/common/types/blob.hpp" #include "duckdb/common/types/time.hpp" #include "duckdb/common/types/value.hpp" #include "duckdb/storage/statistics/struct_stats.hpp" +#include "duckdb/storage/statistics/list_stats.hpp" #include "duckdb/planner/filter/constant_filter.hpp" #include "reader/uuid_column_reader.hpp" +#include "duckdb/common/type_visitor.hpp" namespace duckdb { @@ -319,17 +322,102 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, cons } } +static bool ConvertUnshreddedStats(BaseStatistics &result, optional_ptr input_p) { + D_ASSERT(result.GetType().id() == LogicalTypeId::UINTEGER); + + if (!input_p) { + return false; + } + auto &input = *input_p; + D_ASSERT(input.GetType().id() == LogicalTypeId::BLOB); + result.CopyValidity(input); + + auto min = StringStats::Min(input); + auto max = StringStats::Max(input); + + if (!result.CanHaveNoNull()) { + return true; + } + + if (min.empty() && max.empty()) { + //! All non-shredded values are NULL or VARIANT_NULL, set the stats to indicate this + NumericStats::SetMin(result, 0); + NumericStats::SetMax(result, 0); + result.SetHasNoNull(); + } + return true; +} + +static bool ConvertShreddedStats(BaseStatistics &result, optional_ptr input_p); + +static bool ConvertShreddedStatsItem(BaseStatistics &result, BaseStatistics &input) { + D_ASSERT(result.GetType().id() == LogicalTypeId::STRUCT); + D_ASSERT(input.GetType().id() == LogicalTypeId::STRUCT); + + // result variant stats + auto &untyped_value_index_stats = StructStats::GetChildStats(result, VariantStats::UNTYPED_VALUE_INDEX); + auto &typed_value_result = StructStats::GetChildStats(result, VariantStats::TYPED_VALUE_INDEX); + + // input parquet stats + auto &value_stats = StructStats::GetChildStats(input, 0); + auto &typed_value_input = StructStats::GetChildStats(input, 1); + + if (!ConvertUnshreddedStats(untyped_value_index_stats, value_stats)) { + return false; + } + if (!ConvertShreddedStats(typed_value_result, typed_value_input)) { + return false; + } + return true; +} + +static bool ConvertShreddedStats(BaseStatistics &result, optional_ptr input_p) { + if (!input_p) { + return false; + } + auto &input = *input_p; + result.CopyValidity(input); + + auto type_id = result.GetType().id(); + if (type_id == LogicalTypeId::LIST) { + auto &child_result = ListStats::GetChildStats(result); + auto &child_input = ListStats::GetChildStats(input); + return ConvertShreddedStatsItem(child_result, child_input); + } + if (type_id == LogicalTypeId::STRUCT) { + auto field_count = StructType::GetChildCount(result.GetType()); + for (idx_t i = 0; i < field_count; i++) { + auto &result_field = StructStats::GetChildStats(result, i); + auto &input_field = StructStats::GetChildStats(input, i); + if (!ConvertShreddedStatsItem(result_field, input_field)) { + return false; + } + } + return true; + } + result.Copy(input); + return true; +} + unique_ptr ParquetStatisticsUtils::TransformColumnStatistics(const ParquetColumnSchema &schema, const vector &columns, bool can_have_nan) { // Not supported types auto &type = schema.type; - if (type.id() == LogicalTypeId::ARRAY || type.id() == LogicalTypeId::MAP || type.id() == LogicalTypeId::LIST) { + if (type.id() == LogicalTypeId::ARRAY || type.id() == LogicalTypeId::MAP) { return nullptr; } unique_ptr row_group_stats; + if (type.id() == LogicalTypeId::LIST) { + auto list_stats = ListStats::CreateUnknown(type); + auto &child_schema = schema.children[0]; + auto child_stats = ParquetStatisticsUtils::TransformColumnStatistics(child_schema, columns, can_have_nan); + ListStats::SetChildStats(list_stats, std::move(child_stats)); + row_group_stats = list_stats.ToUnique(); + return row_group_stats; + } // Structs are handled differently (they dont have stats) if (type.id() == LogicalTypeId::STRUCT) { auto struct_stats = StructStats::CreateUnknown(type); @@ -340,19 +428,52 @@ unique_ptr ParquetStatisticsUtils::TransformColumnStatistics(con StructStats::SetChildStats(struct_stats, i, std::move(child_stats)); } row_group_stats = struct_stats.ToUnique(); - - // null count is generic - if (row_group_stats) { - row_group_stats->Set(StatsInfo::CAN_HAVE_NULL_AND_VALID_VALUES); - } return row_group_stats; } else if (schema.schema_type == ParquetColumnSchemaType::VARIANT) { - //! FIXME: there are situations where VARIANT columns can have stats - return nullptr; + auto children_count = schema.children.size(); + if (children_count != 3) { + return nullptr; + } + //! Create the VARIANT stats + auto &typed_value = schema.children[2]; + LogicalType logical_type; + if (!VariantColumnReader::TypedValueLayoutToType(typed_value.type, logical_type)) { + //! We couldn't convert the parquet typed_value to a structured type (likely because a nested 'typed_value' + //! field is missing) + return nullptr; + } + auto shredding_type = TypeVisitor::VisitReplace(logical_type, [](const LogicalType &type) { + return LogicalType::STRUCT({{"typed_value", type}, {"untyped_value_index", LogicalType::UINTEGER}}); + }); + auto variant_stats = VariantStats::CreateShredded(shredding_type); + + //! Take the root stats + auto &shredded_stats = VariantStats::GetShreddedStats(variant_stats); + auto &untyped_value_index_stats = StructStats::GetChildStats(shredded_stats, VariantStats::UNTYPED_VALUE_INDEX); + auto &typed_value_stats = StructStats::GetChildStats(shredded_stats, VariantStats::TYPED_VALUE_INDEX); + + //! Convert the root 'value' -> 'untyped_value_index' + auto &value = schema.children[1]; + D_ASSERT(value.name == "value"); + auto value_stats = ParquetStatisticsUtils::TransformColumnStatistics(value, columns, can_have_nan); + if (!ConvertUnshreddedStats(untyped_value_index_stats, value_stats.get())) { + //! Couldn't convert the stats, or there are no stats + return nullptr; + } + + auto parquet_typed_value_stats = + ParquetStatisticsUtils::TransformColumnStatistics(typed_value, columns, can_have_nan); + if (!ConvertShreddedStats(typed_value_stats, parquet_typed_value_stats.get())) { + //! Couldn't convert the stats, or there are no stats + return nullptr; + } + //! Set validity to UNKNOWN + variant_stats.SetHasNoNull(); + variant_stats.SetHasNull(); + return variant_stats.ToUnique(); } // Otherwise, its a standard column with stats - auto &column_chunk = columns[schema.column_index]; if (!column_chunk.__isset.meta_data || !column_chunk.meta_data.__isset.statistics) { // no stats present for row group @@ -393,16 +514,18 @@ unique_ptr ParquetStatisticsUtils::TransformColumnStatistics(con row_group_stats = CreateNumericStats(type, schema, parquet_stats); } break; + case LogicalTypeId::BLOB: case LogicalTypeId::VARCHAR: { auto string_stats = StringStats::CreateUnknown(type); - if (parquet_stats.__isset.min_value && StringColumnReader::IsValid(parquet_stats.min_value, true)) { + const bool is_varchar = type.id() == LogicalTypeId::VARCHAR; + if (parquet_stats.__isset.min_value && StringColumnReader::IsValid(parquet_stats.min_value, is_varchar)) { StringStats::SetMin(string_stats, parquet_stats.min_value); - } else if (parquet_stats.__isset.min && StringColumnReader::IsValid(parquet_stats.min, true)) { + } else if (parquet_stats.__isset.min && StringColumnReader::IsValid(parquet_stats.min, is_varchar)) { StringStats::SetMin(string_stats, parquet_stats.min); } - if (parquet_stats.__isset.max_value && StringColumnReader::IsValid(parquet_stats.max_value, true)) { + if (parquet_stats.__isset.max_value && StringColumnReader::IsValid(parquet_stats.max_value, is_varchar)) { StringStats::SetMax(string_stats, parquet_stats.max_value); - } else if (parquet_stats.__isset.max && StringColumnReader::IsValid(parquet_stats.max, true)) { + } else if (parquet_stats.__isset.max && StringColumnReader::IsValid(parquet_stats.max, is_varchar)) { StringStats::SetMax(string_stats, parquet_stats.max); } row_group_stats = string_stats.ToUnique(); @@ -456,7 +579,9 @@ unique_ptr ParquetStatisticsUtils::TransformColumnStatistics(con break; } default: - // no stats for you + // no specific stats, only create unknown stats to hold validity information + auto unknown_stats = BaseStatistics::CreateUnknown(type); + row_group_stats = unknown_stats.ToUnique(); break; } // end of type switch diff --git a/src/duckdb/extension/parquet/parquet_writer.cpp b/src/duckdb/extension/parquet/parquet_writer.cpp index e5b4427e7..f7928647a 100644 --- a/src/duckdb/extension/parquet/parquet_writer.cpp +++ b/src/duckdb/extension/parquet/parquet_writer.cpp @@ -22,6 +22,7 @@ #include "duckdb/parser/parsed_data/create_table_function_info.hpp" #include "duckdb/common/types/blob.hpp" #include "duckdb/common/types/geometry_crs.hpp" +#include "writer/variant_column_writer.hpp" namespace duckdb { @@ -150,7 +151,7 @@ Type::type ParquetWriter::DuckDBTypeToParquetType(const LogicalType &duckdb_type } void ParquetWriter::SetSchemaProperties(const LogicalType &duckdb_type, duckdb_parquet::SchemaElement &schema_ele, - bool allow_geometry) { + bool allow_geometry, ClientContext &context) { if (duckdb_type.IsJSONType()) { schema_ele.converted_type = ConvertedType::JSON; schema_ele.__isset.converted_type = true; @@ -268,6 +269,18 @@ void ParquetWriter::SetSchemaProperties(const LogicalType &duckdb_type, duckdb_p schema_ele.logicalType.__isset.GEOMETRY = true; if (GeoType::HasCRS(duckdb_type)) { const auto &crs = GeoType::GetCRS(duckdb_type); + + if (crs.GetType() != CoordinateReferenceSystemType::PROJJSON) { + // Try to convert to GeoJSON + const auto lookup = + CoordinateReferenceSystem::TryConvert(context, crs, CoordinateReferenceSystemType::PROJJSON); + if (lookup) { + schema_ele.logicalType.GEOMETRY.__isset.crs = true; + schema_ele.logicalType.GEOMETRY.crs = lookup->GetDefinition(); + break; + } + } + schema_ele.logicalType.GEOMETRY.__isset.crs = true; schema_ele.logicalType.GEOMETRY.crs = crs.GetDefinition(); } @@ -314,7 +327,10 @@ struct ColumnStatsUnifier { string column_name; string global_min; string global_max; + //! Only set by the 'metadata' of the VARIANT column + string variant_type; idx_t null_count = 0; + idx_t num_values = 0; bool all_min_max_set = true; bool all_nulls_set = true; bool min_is_set = false; @@ -363,7 +379,7 @@ ParquetWriter::ParquetWriter(ClientContext &context, FileSystem &fs, string file shared_ptr encryption_config_p, optional_idx dictionary_size_limit_p, idx_t string_dictionary_page_size_limit_p, bool enable_bloom_filters_p, double bloom_filter_false_positive_ratio_p, - int64_t compression_level_p, bool debug_use_openssl_p, ParquetVersion parquet_version, + int64_t compression_level_p, ParquetVersion parquet_version, GeoParquetVersion geoparquet_version) : context(context), file_name(std::move(file_name_p)), sql_types(std::move(types_p)), column_names(std::move(names_p)), codec(codec), field_ids(std::move(field_ids_p)), @@ -372,26 +388,14 @@ ParquetWriter::ParquetWriter(ClientContext &context, FileSystem &fs, string file string_dictionary_page_size_limit(string_dictionary_page_size_limit_p), enable_bloom_filters(enable_bloom_filters_p), bloom_filter_false_positive_ratio(bloom_filter_false_positive_ratio_p), compression_level(compression_level_p), - debug_use_openssl(debug_use_openssl_p), parquet_version(parquet_version), geoparquet_version(geoparquet_version), - total_written(0), num_row_groups(0) { + parquet_version(parquet_version), geoparquet_version(geoparquet_version), total_written(0), num_row_groups(0) { // initialize the file writer writer = make_uniq(fs, file_name.c_str(), FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_FILE_CREATE_NEW); if (encryption_config) { - auto &config = DBConfig::GetConfig(context); - - // To ensure we can write, we need to autoload httpfs - if (!config.encryption_util || !config.encryption_util->SupportsEncryption()) { - ExtensionHelper::TryAutoLoadExtension(context, "httpfs"); - } - - if (config.encryption_util && debug_use_openssl) { - // Use OpenSSL - encryption_util = config.encryption_util; - } else { - encryption_util = make_shared_ptr(); - } + // Get the encryption util + encryption_util = context.db->GetEncryptionUtil(false); // encrypted parquet files start with the string "PARE" writer->WriteData(const_data_ptr_cast("PARE"), 4); // we only support this one for now, not "AES_GCM_CTR_V1" @@ -411,11 +415,6 @@ ParquetWriter::ParquetWriter(ClientContext &context, FileSystem &fs, string file file_meta_data.created_by = StringUtil::Format("DuckDB version %s (build %s)", DuckDB::LibraryVersion(), DuckDB::SourceID()); - duckdb_parquet::ColumnOrder column_order; - column_order.__set_TYPE_ORDER(duckdb_parquet::TypeDefinedOrder()); - file_meta_data.column_orders.resize(column_names.size(), column_order); - file_meta_data.__isset.column_orders = true; - for (auto &kv_pair : kv_metadata) { duckdb_parquet::KeyValue kv; kv.__set_key(kv_pair.first); @@ -510,25 +509,6 @@ void ParquetWriter::InitializePreprocessing(unique_ptr(context, transformed_types, std::move(transform_expressions)); } -void ParquetWriter::InitializeSchemaElements() { - //! Populate the schema elements of the parquet file we're writing - lock_guard glock(lock); - if (!file_meta_data.schema.empty()) { - return; - } - // populate root schema object - file_meta_data.schema.resize(1); - file_meta_data.schema[0].name = "duckdb_schema"; - file_meta_data.schema[0].num_children = NumericCast(sql_types.size()); - file_meta_data.schema[0].__isset.num_children = true; - file_meta_data.schema[0].repetition_type = duckdb_parquet::FieldRepetitionType::REQUIRED; - file_meta_data.schema[0].__isset.repetition_type = true; - - for (auto &column_writer : column_writers) { - column_writer->FinalizeSchema(file_meta_data.schema); - } -} - void ParquetWriter::PrepareRowGroup(ColumnDataCollection &raw_buffer, PreparedRowGroup &result, unique_ptr &transform_data) { AnalyzeSchema(raw_buffer, column_writers); @@ -959,6 +939,20 @@ static unique_ptr GetBaseStatsUnifier(const LogicalType &typ } } +static bool IsVariantMetadataField(const ColumnWriter &writer) { + if (!writer.parent) { + //! Not a nested column + return false; + } + auto &parent = *writer.parent; + if (parent.Type().id() != LogicalTypeId::VARIANT) { + //! (direct) parent is not a VARIANT + return false; + } + auto &name = writer.Schema().name; + return name == "metadata"; +} + static void GetStatsUnifier(const ColumnWriter &column_writer, vector> &unifiers, string base_name = string()) { auto &schema = column_writer.Schema(); @@ -973,6 +967,12 @@ static void GetStatsUnifier(const ColumnWriter &column_writer, vectorcolumn_name = std::move(base_name); + + if (IsVariantMetadataField(column_writer)) { + //! Stamp the 'metadata' field of the VARIANT with the internal layout of the VARIANT + auto &variant_writer = column_writer.parent->Cast(); + unifier->variant_type = variant_writer.TransformedType().ToString(); + } unifiers.push_back(std::move(unifier)); return; } @@ -986,6 +986,7 @@ void ParquetWriter::FlushColumnStats(idx_t col_idx, duckdb_parquet::ColumnChunk if (!written_stats) { return; } + // push the stats of this column into the unifier auto &stats_unifier = stats_accumulator->stats_unifiers[col_idx]; bool has_nan = false; @@ -1013,6 +1014,7 @@ void ParquetWriter::FlushColumnStats(idx_t col_idx, duckdb_parquet::ColumnChunk stats_unifier->UnifyGeoStats(*writer_stats->GetGeoStats()); } stats_unifier->column_size_bytes += column.meta_data.total_compressed_size; + stats_unifier->num_values += column.meta_data.num_values; } } @@ -1024,6 +1026,7 @@ void ParquetWriter::GatherWrittenStatistics() { auto &stats_unifier = stats_accumulator->stats_unifiers[c]; case_insensitive_map_t column_stats; column_stats["column_size_bytes"] = Value::UBIGINT(stats_unifier->column_size_bytes); + column_stats["num_values"] = Value::UBIGINT(stats_unifier->num_values); if (stats_unifier->all_min_max_set) { auto min_value = stats_unifier->StatsToString(stats_unifier->global_min); auto max_value = stats_unifier->StatsToString(stats_unifier->global_max); @@ -1034,6 +1037,9 @@ void ParquetWriter::GatherWrittenStatistics() { column_stats["max"] = max_value; } } + if (!stats_unifier->variant_type.empty()) { + column_stats["variant_type"] = Value(stats_unifier->variant_type); + } if (stats_unifier->all_nulls_set) { column_stats["null_count"] = Value::UBIGINT(stats_unifier->null_count); } @@ -1069,8 +1075,39 @@ void ParquetWriter::GatherWrittenStatistics() { column_stats["geo_types"] = Value::LIST(type_strings); } } - written_stats->column_statistics.insert(make_pair(stats_unifier->column_name, std::move(column_stats))); + written_stats->column_statistics.emplace(stats_unifier->column_name, std::move(column_stats)); + } +} + +void ParquetWriter::InitializeSchemaElements() { + //! Populate the schema elements of the parquet file we're writing + lock_guard glock(lock); + if (!file_meta_data.schema.empty()) { + return; + } + // populate root schema object + file_meta_data.schema.resize(1); + file_meta_data.schema[0].name = "duckdb_schema"; + file_meta_data.schema[0].num_children = NumericCast(sql_types.size()); + file_meta_data.schema[0].__isset.num_children = true; + file_meta_data.schema[0].repetition_type = duckdb_parquet::FieldRepetitionType::REQUIRED; + file_meta_data.schema[0].__isset.repetition_type = true; + + idx_t unique_columns = 0; + for (auto &column_writer : column_writers) { + unique_columns += column_writer->FinalizeSchema(file_meta_data.schema); + } + + if (written_stats) { + for (auto &column_writer : column_writers) { + GetStatsUnifier(*column_writer, stats_accumulator->stats_unifiers); + } } + + duckdb_parquet::ColumnOrder column_order; + column_order.__set_TYPE_ORDER(duckdb_parquet::TypeDefinedOrder()); + file_meta_data.column_orders.resize(unique_columns, column_order); + file_meta_data.__isset.column_orders = true; } void ParquetWriter::Finalize() { @@ -1166,10 +1203,7 @@ void ParquetWriter::BufferBloomFilter(idx_t col_idx, unique_ptr(); - // create the per-column stats unifiers - for (auto &column_writer : column_writers) { - GetStatsUnifier(*column_writer, stats_accumulator->stats_unifiers); - } + //! NOTE: the actual accumulators for the writers are created after FinalizeSchema() is called } } // namespace duckdb diff --git a/src/duckdb/extension/parquet/reader/string_column_reader.cpp b/src/duckdb/extension/parquet/reader/string_column_reader.cpp index e6bde0c19..1997e80bc 100644 --- a/src/duckdb/extension/parquet/reader/string_column_reader.cpp +++ b/src/duckdb/extension/parquet/reader/string_column_reader.cpp @@ -31,10 +31,11 @@ bool StringColumnReader::IsValid(const char *str_data, uint32_t str_len, const b bool StringColumnReader::IsValid(const string &str, bool is_varchar) { return IsValid(str.c_str(), str.size(), is_varchar); } -void StringColumnReader::VerifyString(const char *str_data, uint32_t str_len, const bool is_varchar) { +void StringColumnReader::VerifyString(const char *str_data, uint32_t str_len, const bool is_varchar) const { if (!IsValid(str_data, str_len, is_varchar)) { - throw InvalidInputException("Invalid string encoding found in Parquet file: value \"%s\" is not valid UTF8!", - Blob::ToString(string_t(str_data, str_len))); + throw InvalidInputException( + "Invalid string encoding found in Parquet file \"%s\": value \"%s\" is not valid UTF8!", + reader.GetFileName(), Blob::ToString(string_t(str_data, str_len))); } } diff --git a/src/duckdb/extension/parquet/reader/variant/variant_binary_decoder.cpp b/src/duckdb/extension/parquet/reader/variant/variant_binary_decoder.cpp index 0388da0b3..8d69660b6 100644 --- a/src/duckdb/extension/parquet/reader/variant/variant_binary_decoder.cpp +++ b/src/duckdb/extension/parquet/reader/variant/variant_binary_decoder.cpp @@ -120,9 +120,12 @@ static T DecodeDecimal(const_data_ptr_t data, uint8_t &scale, uint8_t &width) { data++; auto result = Load(data); - //! FIXME: The spec says: - //! The implied precision of a decimal value is `floor(log_10(val)) + 1` - width = DecimalWidth::max; + auto abs_val = result; + if (abs_val < 0) { + abs_val = -abs_val; + } + uint8_t digits = floor(log10(abs_val)) + 1; + width = digits; return result; } @@ -181,24 +184,21 @@ VariantValue VariantBinaryDecoder::PrimitiveTypeDecode(const VariantValueMetadat uint8_t width; auto value = DecodeDecimal(data, scale, width); - auto value_str = Decimal::ToString(value, width, scale); - return VariantValue(Value(value_str)); + return VariantValue(Value::DECIMAL(value, width, scale)); } case VariantPrimitiveType::DECIMAL8: { uint8_t scale; uint8_t width; auto value = DecodeDecimal(data, scale, width); - auto value_str = Decimal::ToString(value, width, scale); - return VariantValue(Value(value_str)); + return VariantValue(Value::DECIMAL(value, width, scale)); } case VariantPrimitiveType::DECIMAL16: { uint8_t scale; uint8_t width; auto value = DecodeDecimal(data, scale, width); - auto value_str = Decimal::ToString(value, width, scale); - return VariantValue(Value(value_str)); + return VariantValue(Value::DECIMAL(value, width, scale)); } case VariantPrimitiveType::DATE: { date_t value; @@ -215,8 +215,7 @@ VariantValue VariantBinaryDecoder::PrimitiveTypeDecode(const VariantValueMetadat micros_ts.value = Load(data); auto value = Value::TIMESTAMP(micros_ts); - auto value_str = value.ToString(); - return VariantValue(Value(value_str)); + return VariantValue(std::move(value)); } case VariantPrimitiveType::BINARY: { //! Follow the JSON serialization guide by converting BINARY to Base64: @@ -252,13 +251,11 @@ VariantValue VariantBinaryDecoder::PrimitiveTypeDecode(const VariantValueMetadat nanos_ts.value = Load(data); auto value = Value::TIMESTAMPNS(nanos_ts); - auto value_str = value.ToString(); - return VariantValue(Value(value_str)); + return VariantValue(std::move(value)); } case VariantPrimitiveType::UUID: { auto uuid_value = UUIDValueConversion::ReadParquetUUID(data); - auto value_str = UUID::ToString(uuid_value); - return VariantValue(Value(value_str)); + return VariantValue(Value::UUID(uuid_value)); } default: throw NotImplementedException("Variant PrimitiveTypeDecode not implemented for type (%d)", diff --git a/src/duckdb/extension/parquet/reader/variant/variant_shredded_conversion.cpp b/src/duckdb/extension/parquet/reader/variant/variant_shredded_conversion.cpp index b96304d98..ac78ae84b 100644 --- a/src/duckdb/extension/parquet/reader/variant/variant_shredded_conversion.cpp +++ b/src/duckdb/extension/parquet/reader/variant/variant_shredded_conversion.cpp @@ -60,18 +60,15 @@ VariantValue ConvertShreddedValue::Convert(double val) { //! decimal4/decimal8/decimal16 template <> VariantValue ConvertShreddedValue::ConvertDecimal(int32_t val, uint8_t width, uint8_t scale) { - auto value_str = Decimal::ToString(val, width, scale); - return VariantValue(Value(value_str)); + return VariantValue(Value::DECIMAL(val, width, scale)); } template <> VariantValue ConvertShreddedValue::ConvertDecimal(int64_t val, uint8_t width, uint8_t scale) { - auto value_str = Decimal::ToString(val, width, scale); - return VariantValue(Value(value_str)); + return VariantValue(Value::DECIMAL(val, width, scale)); } template <> VariantValue ConvertShreddedValue::ConvertDecimal(hugeint_t val, uint8_t width, uint8_t scale) { - auto value_str = Decimal::ToString(val, width, scale); - return VariantValue(Value(value_str)); + return VariantValue(Value::DECIMAL(val, width, scale)); } //! date template <> @@ -119,7 +116,7 @@ VariantValue ConvertShreddedValue::Convert(string_t val) { //! uuid template <> VariantValue ConvertShreddedValue::Convert(hugeint_t val) { - return VariantValue(Value(UUID::ToString(val))); + return VariantValue(Value::UUID(val)); } template diff --git a/src/duckdb/extension/parquet/reader/variant_column_reader.cpp b/src/duckdb/extension/parquet/reader/variant_column_reader.cpp index 635bfbbb5..c9d6b9798 100644 --- a/src/duckdb/extension/parquet/reader/variant_column_reader.cpp +++ b/src/duckdb/extension/parquet/reader/variant_column_reader.cpp @@ -135,4 +135,73 @@ idx_t VariantColumnReader::GroupRowsAvailable() { throw InternalException("No projected columns in struct?"); } +bool VariantColumnReader::TypedValueLayoutToType(const LogicalType &typed_value, LogicalType &output) { + if (!typed_value.IsNested()) { + output = typed_value; + return true; + } + auto type_id = typed_value.id(); + if (type_id == LogicalTypeId::STRUCT) { + //! OBJECT (...) + auto &object_fields = StructType::GetChildTypes(typed_value); + child_list_t children; + for (auto &object_field : object_fields) { + auto &name = object_field.first; + auto &field = object_field.second; + //! : { + //! value: BLOB, + //! typed_value: + //! } + auto &field_children = StructType::GetChildTypes(field); + idx_t index = DConstants::INVALID_INDEX; + for (idx_t i = 0; i < field_children.size(); i++) { + if (field_children[i].first == "typed_value") { + index = i; + break; + } + } + if (index == DConstants::INVALID_INDEX) { + //! FIXME: we might be able to just omit this field from the OBJECT, instead of flat-out failing the + //! conversion No 'typed_value' field, so we can't assign a structured type to this field at all + return false; + } + LogicalType child_type; + if (!TypedValueLayoutToType(field_children[index].second, child_type)) { + return false; + } + children.emplace_back(name, child_type); + } + output = LogicalType::STRUCT(std::move(children)); + return true; + } + if (type_id == LogicalTypeId::LIST) { + //! ARRAY + auto &element = ListType::GetChildType(typed_value); + //! element: { + //! value: BLOB, + //! typed_value: + //! } + auto &element_children = StructType::GetChildTypes(element); + idx_t index = DConstants::INVALID_INDEX; + for (idx_t i = 0; i < element_children.size(); i++) { + if (element_children[i].first == "typed_value") { + index = i; + break; + } + } + if (index == DConstants::INVALID_INDEX) { + //! This *might* be allowed by the spec, it's hard to reason about.. + return false; + } + LogicalType child_type; + if (!TypedValueLayoutToType(element_children[index].second, child_type)) { + return false; + } + output = LogicalType::LIST(child_type); + return true; + } + throw InvalidInputException("VARIANT typed value has to be a primitive/struct/list, not %s", + typed_value.ToString()); +} + } // namespace duckdb diff --git a/src/duckdb/extension/parquet/serialize_parquet.cpp b/src/duckdb/extension/parquet/serialize_parquet.cpp index 6f12d5d89..76f864368 100644 --- a/src/duckdb/extension/parquet/serialize_parquet.cpp +++ b/src/duckdb/extension/parquet/serialize_parquet.cpp @@ -82,7 +82,7 @@ void ParquetOptionsSerialization::Serialize(Serializer &serializer) const { serializer.WriteProperty(102, "file_options", file_options); serializer.WritePropertyWithDefault>(103, "schema", parquet_options.schema); serializer.WritePropertyWithDefault>(104, "encryption_config", parquet_options.encryption_config, nullptr); - serializer.WritePropertyWithDefault(105, "debug_use_openssl", parquet_options.debug_use_openssl, true); + /* [Deleted] (bool) "parquet_options.debug_use_openssl" */ serializer.WritePropertyWithDefault(106, "explicit_cardinality", parquet_options.explicit_cardinality, 0); serializer.WritePropertyWithDefault(107, "can_have_nan", parquet_options.can_have_nan, false); } @@ -94,7 +94,7 @@ ParquetOptionsSerialization ParquetOptionsSerialization::Deserialize(Deserialize deserializer.ReadProperty(102, "file_options", result.file_options); deserializer.ReadPropertyWithDefault>(103, "schema", result.parquet_options.schema); deserializer.ReadPropertyWithExplicitDefault>(104, "encryption_config", result.parquet_options.encryption_config, nullptr); - deserializer.ReadPropertyWithExplicitDefault(105, "debug_use_openssl", result.parquet_options.debug_use_openssl, true); + deserializer.ReadDeletedProperty(105, "debug_use_openssl"); deserializer.ReadPropertyWithExplicitDefault(106, "explicit_cardinality", result.parquet_options.explicit_cardinality, 0); deserializer.ReadPropertyWithExplicitDefault(107, "can_have_nan", result.parquet_options.can_have_nan, false); return result; diff --git a/src/duckdb/extension/parquet/writer/list_column_writer.cpp b/src/duckdb/extension/parquet/writer/list_column_writer.cpp index a54017f23..b0d590eec 100644 --- a/src/duckdb/extension/parquet/writer/list_column_writer.cpp +++ b/src/duckdb/extension/parquet/writer/list_column_writer.cpp @@ -146,7 +146,12 @@ ColumnWriter &ListColumnWriter::GetChildWriter() { return *child_writers[0]; } -void ListColumnWriter::FinalizeSchema(vector &schemas) { +const ColumnWriter &ListColumnWriter::GetChildWriter() const { + D_ASSERT(child_writers.size() == 1); + return *child_writers[0]; +} + +idx_t ListColumnWriter::FinalizeSchema(vector &schemas) { idx_t schema_idx = schemas.size(); auto &schema = column_schema; @@ -189,7 +194,7 @@ void ListColumnWriter::FinalizeSchema(vector &sch //! Instead, the "key_value" struct will be marked as REPEATED D_ASSERT(GetChildWriter().Schema().repetition_type == FieldRepetitionType::REPEATED); } - GetChildWriter().FinalizeSchema(schemas); + return GetChildWriter().FinalizeSchema(schemas); } } // namespace duckdb diff --git a/src/duckdb/extension/parquet/writer/primitive_column_writer.cpp b/src/duckdb/extension/parquet/writer/primitive_column_writer.cpp index dcaf80520..a357bfb59 100644 --- a/src/duckdb/extension/parquet/writer/primitive_column_writer.cpp +++ b/src/duckdb/extension/parquet/writer/primitive_column_writer.cpp @@ -264,11 +264,11 @@ void PrimitiveColumnWriter::SetParquetStatistics(PrimitiveColumnWriterState &sta if (!state.stats_state) { return; } - if (MaxRepeat() == 0) { - column_chunk.meta_data.statistics.null_count = NumericCast(state.null_count); - column_chunk.meta_data.statistics.__isset.null_count = true; - column_chunk.meta_data.__isset.statistics = true; - } + auto null_count = MaxRepeat() == 0 ? state.null_count : state.null_count + state.parent_null_count; + column_chunk.meta_data.statistics.null_count = NumericCast(null_count); + column_chunk.meta_data.statistics.__isset.null_count = true; + column_chunk.meta_data.__isset.statistics = true; + // if we have NaN values - don't write the min/max here if (!state.stats_state->HasNaN()) { // set min/max/min_value/max_value @@ -321,7 +321,7 @@ void PrimitiveColumnWriter::SetParquetStatistics(PrimitiveColumnWriterState &sta } if (has_json_stats) { // Add the geospatial statistics to the extra GeoParquet metadata - writer.GetGeoParquetData().AddGeoParquetStats(column_schema.name, column_schema.type, + writer.GetGeoParquetData().AddGeoParquetStats(writer.GetContext(), column_schema.name, column_schema.type, *state.stats_state->GetGeoStats(), gpq_version); } } @@ -382,7 +382,6 @@ void PrimitiveColumnWriter::FinalizeWrite(ColumnWriterState &state_p) { if (state.bloom_filter) { writer.BufferBloomFilter(state.col_idx, std::move(state.bloom_filter)); } - // finalize the stats writer.FlushColumnStats(state.col_idx, column_chunk, state.stats_state.get()); } @@ -431,7 +430,7 @@ void PrimitiveColumnWriter::WriteDictionary(PrimitiveColumnWriterState &state, u state.write_info.insert(state.write_info.begin(), std::move(write_info)); } -void PrimitiveColumnWriter::FinalizeSchema(vector &schemas) { +idx_t PrimitiveColumnWriter::FinalizeSchema(vector &schemas) { idx_t schema_idx = schemas.size(); auto &schema = column_schema; @@ -454,10 +453,11 @@ void PrimitiveColumnWriter::FinalizeSchema(vector schema_element.__isset.field_id = true; schema_element.field_id = field_id.GetIndex(); } - ParquetWriter::SetSchemaProperties(type, schema_element, allow_geometry); + ParquetWriter::SetSchemaProperties(type, schema_element, allow_geometry, writer.GetContext()); schemas.push_back(std::move(schema_element)); D_ASSERT(child_writers.empty()); + return 1; } } // namespace duckdb diff --git a/src/duckdb/extension/parquet/writer/struct_column_writer.cpp b/src/duckdb/extension/parquet/writer/struct_column_writer.cpp index a792b736b..d17b32d06 100644 --- a/src/duckdb/extension/parquet/writer/struct_column_writer.cpp +++ b/src/duckdb/extension/parquet/writer/struct_column_writer.cpp @@ -105,7 +105,7 @@ void StructColumnWriter::FinalizeWrite(ColumnWriterState &state_p) { } } -void StructColumnWriter::FinalizeSchema(vector &schemas) { +idx_t StructColumnWriter::FinalizeSchema(vector &schemas) { idx_t schema_idx = schemas.size(); auto &schema = column_schema; @@ -129,9 +129,11 @@ void StructColumnWriter::FinalizeSchema(vector &s } schemas.push_back(std::move(schema_element)); + idx_t unique_columns = 0; for (auto &child_writer : child_writers) { - child_writer->FinalizeSchema(schemas); + unique_columns += child_writer->FinalizeSchema(schemas); } + return unique_columns; } } // namespace duckdb diff --git a/src/duckdb/extension/parquet/writer/variant/analyze_variant.cpp b/src/duckdb/extension/parquet/writer/variant/analyze_variant.cpp index c7575d09f..b6a244073 100644 --- a/src/duckdb/extension/parquet/writer/variant/analyze_variant.cpp +++ b/src/duckdb/extension/parquet/writer/variant/analyze_variant.cpp @@ -14,6 +14,7 @@ unique_ptr VariantColumnWriter::AnalyzeSchemaInit() { static void AnalyzeSchemaInternal(VariantAnalyzeData &state, UnifiedVariantVectorData &variant, idx_t row, uint32_t values_index) { + state.total_count++; if (!variant.RowIsValid(row)) { state.type_map[static_cast(VariantLogicalType::VARIANT_NULL)]++; return; @@ -50,19 +51,19 @@ static void AnalyzeSchemaInternal(VariantAnalyzeData &state, UnifiedVariantVecto } } else if (type_id == VariantLogicalType::DECIMAL) { auto decimal_data = VariantUtils::DecodeDecimalData(variant, row, values_index); - auto physical_type = decimal_data.GetPhysicalType(); - switch (physical_type) { - case PhysicalType::INT32: - state.decimal_type_map[0]++; - break; - case PhysicalType::INT64: - state.decimal_type_map[1]++; - break; - case PhysicalType::INT128: - state.decimal_type_map[2]++; - break; - default: - break; + auto decimal_count = state.type_map[static_cast(VariantLogicalType::DECIMAL)]; + decimal_count--; + if (!decimal_count) { + state.decimal_width = decimal_data.width; + state.decimal_scale = decimal_data.scale; + state.decimal_consistent = true; + return; + } + if (!state.decimal_consistent) { + return; + } + if (decimal_data.width != state.decimal_width || decimal_data.scale != state.decimal_scale) { + state.decimal_consistent = false; } } else if (type_id == VariantLogicalType::BOOL_FALSE) { //! Move it to bool_true to have the counts all in one place @@ -87,8 +88,7 @@ namespace { struct ShredAnalysisState { idx_t highest_count = 0; - LogicalTypeId type_id; - PhysicalType decimal_type; + LogicalType type; }; } // namespace @@ -96,36 +96,30 @@ struct ShredAnalysisState { template static void CheckPrimitive(const VariantAnalyzeData &state, ShredAnalysisState &result) { auto count = state.type_map[static_cast(VARIANT_TYPE)]; + if (count <= result.highest_count) { + return; + } if (VARIANT_TYPE == VariantLogicalType::DECIMAL) { - if (!count) { + D_ASSERT(count); + if (!state.decimal_consistent) { return; } - auto int32_count = state.decimal_type_map[0]; - if (int32_count > result.highest_count) { - result.type_id = LogicalTypeId::DECIMAL; - result.decimal_type = PhysicalType::INT32; - } - auto int64_count = state.decimal_type_map[1]; - if (int64_count > result.highest_count) { - result.type_id = LogicalTypeId::DECIMAL; - result.decimal_type = PhysicalType::INT64; - } - auto int128_count = state.decimal_type_map[2]; - if (int128_count > result.highest_count) { - result.type_id = LogicalTypeId::DECIMAL; - result.decimal_type = PhysicalType::INT128; - } + result.highest_count = count; + result.type = LogicalType::DECIMAL(state.decimal_width, state.decimal_scale); } else { - if (count > result.highest_count) { - result.highest_count = count; - result.type_id = SHREDDED_TYPE; - } + result.highest_count = count; + result.type = SHREDDED_TYPE; } } static LogicalType ConstructShreddedType(const VariantAnalyzeData &state) { ShredAnalysisState result; + if (state.type_map[0] == state.total_count) { + //! All NULL, emit INT32 + return LogicalType::INTEGER; + } + CheckPrimitive(state, result); CheckPrimitive(state, result); CheckPrimitive(state, result); @@ -133,9 +127,7 @@ static LogicalType ConstructShreddedType(const VariantAnalyzeData &state) { CheckPrimitive(state, result); CheckPrimitive(state, result); CheckPrimitive(state, result); - //! FIXME: It's not enough for decimals to have the same PhysicalType, their width+scale has to match in order to - //! shred on the type. - // CheckPrimitive(state, result); + CheckPrimitive(state, result); CheckPrimitive(state, result); CheckPrimitive(state, result); CheckPrimitive(state, result); @@ -165,27 +157,19 @@ static LogicalType ConstructShreddedType(const VariantAnalyzeData &state) { return LogicalType::STRUCT(field_types); } } - - if (result.type_id == LogicalTypeId::DECIMAL) { - //! TODO: what should the scale be??? - if (result.decimal_type == PhysicalType::INT32) { - return LogicalType::DECIMAL(DecimalWidth::max, 0); - } else if (result.decimal_type == PhysicalType::INT64) { - return LogicalType::DECIMAL(DecimalWidth::max, 0); - } else if (result.decimal_type == PhysicalType::INT128) { - return LogicalType::DECIMAL(DecimalWidth::max, 0); - } - } - return result.type_id; + return result.type; } void VariantColumnWriter::AnalyzeSchemaFinalize(const ParquetAnalyzeSchemaState &state_p) { auto &state = state_p.Cast(); auto shredded_type = ConstructShreddedType(state.analyze_data); - - auto typed_value = TransformTypedValueRecursive(shredded_type); is_analyzed = true; + if (shredded_type.id() == LogicalTypeId::VARIANT || shredded_type.id() == LogicalTypeId::INVALID) { + //! Can't shred, keep the original children + return; + } + auto typed_value = TransformTypedValueRecursive(shredded_type); auto &schema = Schema(); auto &context = writer.GetContext(); D_ASSERT(child_writers.size() == 2); diff --git a/src/duckdb/extension/parquet/writer/variant/convert_variant.cpp b/src/duckdb/extension/parquet/writer/variant/convert_variant.cpp index f7be8c755..2697f4c03 100644 --- a/src/duckdb/extension/parquet/writer/variant/convert_variant.cpp +++ b/src/duckdb/extension/parquet/writer/variant/convert_variant.cpp @@ -5,6 +5,7 @@ #include "reader/variant/variant_binary_decoder.hpp" #include "parquet_shredding.hpp" #include "duckdb/function/variant/variant_shredding.hpp" +#include "duckdb/planner/expression_binder.hpp" namespace duckdb { @@ -162,9 +163,18 @@ struct ParquetVariantShreddingState : public VariantShreddingState { }; struct ParquetVariantShredding : public VariantShredding { + ParquetVariantShredding() { + // for parquet untyped ("value") comes before typed ("typed_value") + untyped_value_index = 0; + typed_value_index = 1; + } + void WriteVariantValues(UnifiedVariantVectorData &variant, Vector &result, optional_ptr sel, optional_ptr value_index_sel, optional_ptr result_sel, idx_t count) override; + +protected: + void WriteMissingField(Vector &vector, idx_t index) override; }; } // namespace @@ -728,6 +738,11 @@ static void CreateValues(UnifiedVariantVectorData &variant, Vector &value, optio } } +void ParquetVariantShredding::WriteMissingField(Vector &vector, idx_t index) { + //! The field is missing, set it to null + FlatVector::SetNull(vector, index, true); +} + void ParquetVariantShredding::WriteVariantValues(UnifiedVariantVectorData &variant, Vector &result, optional_ptr sel, optional_ptr value_index_sel, @@ -809,7 +824,7 @@ static void ToParquetVariant(DataChunk &input, ExpressionState &state, Vector &r } } -void VariantColumnWriter::FinalizeSchema(vector &schemas) { +idx_t VariantColumnWriter::FinalizeSchema(vector &schemas) { idx_t schema_idx = schemas.size(); auto &schema = Schema(); @@ -817,6 +832,7 @@ void VariantColumnWriter::FinalizeSchema(vector & auto &repetition_type = schema.repetition_type; auto &name = schema.name; + auto &field_id = schema.field_id; // variant group duckdb_parquet::SchemaElement top_element; @@ -829,11 +845,17 @@ void VariantColumnWriter::FinalizeSchema(vector & top_element.__isset.num_children = true; top_element.__isset.repetition_type = true; top_element.name = name; + if (field_id.IsValid()) { + top_element.__isset.field_id = true; + top_element.field_id = field_id.GetIndex(); + } schemas.push_back(std::move(top_element)); + idx_t unique_columns = 0; for (auto &child_writer : child_writers) { - child_writer->FinalizeSchema(schemas); + unique_columns += child_writer->FinalizeSchema(schemas); } + return unique_columns; } LogicalType VariantColumnWriter::TransformTypedValueRecursive(const LogicalType &type) { @@ -865,7 +887,7 @@ LogicalType VariantColumnWriter::TransformTypedValueRecursive(const LogicalType case LogicalTypeId::MAP: case LogicalTypeId::VARIANT: case LogicalTypeId::ARRAY: - throw BinderException("'%s' can't appear inside the a 'typed_value' shredded type!", type.ToString()); + throw BinderException("'%s' can't appear inside a 'typed_value' shredded type!", type.ToString()); default: return type; } @@ -875,7 +897,7 @@ static LogicalType GetParquetVariantType(optional_ptr shredding = n child_list_t children; children.emplace_back("metadata", LogicalType::BLOB); children.emplace_back("value", LogicalType::BLOB); - if (shredding) { + if (shredding && shredding->id() != LogicalTypeId::VARIANT) { children.emplace_back("typed_value", VariantColumnWriter::TransformTypedValueRecursive(*shredding)); } auto res = LogicalType::STRUCT(std::move(children)); @@ -906,7 +928,7 @@ static unique_ptr BindTransform(ClientContext &context, ScalarFunc if (type_str.IsNull()) { throw BinderException("Optional second argument 'shredding' can not be NULL"); } - auto shredded_type = TransformStringToLogicalType(type_str.GetValue()); + auto shredded_type = TransformStringToLogicalType(type_str.GetValue(), context); bound_function.SetReturnType(GetParquetVariantType(shredded_type)); } else { bound_function.SetReturnType(GetParquetVariantType()); diff --git a/src/duckdb/src/catalog/catalog.cpp b/src/duckdb/src/catalog/catalog.cpp index 0dec15f20..b66f0452d 100644 --- a/src/duckdb/src/catalog/catalog.cpp +++ b/src/duckdb/src/catalog/catalog.cpp @@ -15,6 +15,7 @@ #include "duckdb/parser/parsed_data/alter_table_info.hpp" #include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" #include "duckdb/parser/parsed_data/create_collation_info.hpp" +#include "duckdb/parser/parsed_data/create_coordinate_system_info.hpp" #include "duckdb/parser/parsed_data/create_copy_function_info.hpp" #include "duckdb/parser/parsed_data/create_index_info.hpp" #include "duckdb/parser/parsed_data/create_pragma_function_info.hpp" @@ -139,6 +140,10 @@ optional_ptr Catalog::CreateTable(ClientContext &context, unique_p optional_ptr Catalog::CreateTable(CatalogTransaction transaction, SchemaCatalogEntry &schema, BoundCreateTableInfo &info) { + auto supports_create_table = SupportsCreateTable(info); + if (supports_create_table.HasError()) { + supports_create_table.Throw(); + } return schema.CreateTable(transaction, info); } @@ -294,6 +299,24 @@ optional_ptr Catalog::CreateCollation(CatalogTransaction transacti return schema.CreateCollation(transaction, info); } +//===--------------------------------------------------------------------===// +// Coordinate System +//===--------------------------------------------------------------------===// +optional_ptr Catalog::CreateCoordinateSystem(CatalogTransaction transaction, + CreateCoordinateSystemInfo &info) { + auto &schema = GetSchema(transaction, info.schema); + return CreateCoordinateSystem(transaction, schema, info); +} + +optional_ptr Catalog::CreateCoordinateSystem(ClientContext &context, CreateCoordinateSystemInfo &info) { + return CreateCoordinateSystem(GetCatalogTransaction(context), info); +} + +optional_ptr Catalog::CreateCoordinateSystem(CatalogTransaction transaction, SchemaCatalogEntry &schema, + CreateCoordinateSystemInfo &info) { + return schema.CreateCoordinateSystem(transaction, info); +} + //===--------------------------------------------------------------------===// // Index //===--------------------------------------------------------------------===// @@ -520,8 +543,7 @@ bool Catalog::TryAutoLoad(ClientContext &context, const string &original_name) n return true; } #ifndef DUCKDB_DISABLE_EXTENSION_LOAD - auto &dbconfig = DBConfig::GetConfig(context); - if (!dbconfig.options.autoload_known_extensions) { + if (!Settings::Get(context)) { return false; } try { @@ -537,8 +559,7 @@ bool Catalog::TryAutoLoad(ClientContext &context, const string &original_name) n String Catalog::AutoloadExtensionByConfigName(ClientContext &context, const String &configuration_name) { #ifndef DUCKDB_DISABLE_EXTENSION_LOAD - auto &dbconfig = DBConfig::GetConfig(context); - if (dbconfig.options.autoload_known_extensions) { + if (Settings::Get(context)) { auto extension_name = ExtensionHelper::FindExtensionInEntries(configuration_name.ToStdString(), EXTENSION_SETTINGS); if (ExtensionHelper::CanAutoloadExtension(extension_name)) { @@ -594,8 +615,7 @@ static bool CompareCatalogTypes(CatalogType type_a, CatalogType type_b) { bool Catalog::AutoLoadExtensionByCatalogEntry(DatabaseInstance &db, CatalogType type, const string &entry_name) { #ifndef DUCKDB_DISABLE_EXTENSION_LOAD - auto &dbconfig = DBConfig::GetConfig(db); - if (dbconfig.options.autoload_known_extensions) { + if (Settings::Get(db)) { string extension_name; if (IsAutoloadableFunction(type)) { auto lookup_result = ExtensionHelper::FindExtensionInFunctionEntries(entry_name, EXTENSION_FUNCTIONS); @@ -640,7 +660,7 @@ CatalogException Catalog::UnrecognizedConfigurationError(ClientContext &context, // the setting is not in an extension // get a list of all options vector potential_names = DBConfig::GetOptionNames(); - for (auto &entry : DBConfig::GetConfig(context).extension_parameters) { + for (auto &entry : DBConfig::GetConfig(context).GetExtensionSettings()) { potential_names.push_back(entry.first); } throw CatalogException::MissingEntry("configuration parameter", name, potential_names); @@ -651,7 +671,7 @@ CatalogException Catalog::CreateMissingEntryException(CatalogEntryRetriever &ret const reference_set_t &schemas) { auto &context = retriever.GetContext(); auto entries = SimilarEntriesInSchemas(context, lookup_info, schemas); - auto max_schema_count = DBConfig::GetSetting(context); + auto max_schema_count = Settings::Get(context); reference_set_t unseen_schemas; auto &db_manager = DatabaseManager::Get(context); @@ -1211,6 +1231,25 @@ optional_ptr Catalog::GetDependencyManager() { return nullptr; } +ErrorData Catalog::SupportsCreateTable(BoundCreateTableInfo &info) { + auto &base = info.Base().Cast(); + if (!base.partition_keys.empty()) { + return ErrorData( + ExceptionType::CATALOG, + StringUtil::Format("PARTITIONED BY is not supported for tables in a %s catalog", GetCatalogType())); + } + if (!base.sort_keys.empty()) { + return ErrorData(ExceptionType::CATALOG, + StringUtil::Format("SORTED BY is not supported for tables in a %s catalog", GetCatalogType())); + } + if (!base.options.empty()) { + return ErrorData( + ExceptionType::CATALOG, + StringUtil::Format("WITH clause is not supported for tables in a %s catalog", GetCatalogType())); + } + return ErrorData(); +} + string Catalog::GetDefaultSchema() const { return DEFAULT_SCHEMA; } diff --git a/src/duckdb/src/catalog/catalog_entry/aggregate_function_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/aggregate_function_catalog_entry.cpp new file mode 100644 index 000000000..e8c653d94 --- /dev/null +++ b/src/duckdb/src/catalog/catalog_entry/aggregate_function_catalog_entry.cpp @@ -0,0 +1,17 @@ +#include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" +#include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" +#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" +#include "duckdb/main/attached_database.hpp" + +namespace duckdb { + +AggregateFunctionCatalogEntry::AggregateFunctionCatalogEntry(Catalog &catalog, SchemaCatalogEntry &schema, + CreateAggregateFunctionInfo &info) + : FunctionEntry(CatalogType::AGGREGATE_FUNCTION_ENTRY, catalog, schema, info), functions(info.functions) { + for (auto &function : functions.functions) { + function.catalog_name = catalog.GetAttached().GetName(); + function.schema_name = schema.name; + } +} + +} // namespace duckdb diff --git a/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp b/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp index 33d0db4da..8f94f0932 100644 --- a/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp @@ -2,6 +2,7 @@ #include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/collate_catalog_entry.hpp" +#include "duckdb/catalog/catalog_entry/coordinate_system_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/copy_function_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/duck_index_entry.hpp" #include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" @@ -14,6 +15,7 @@ #include "duckdb/catalog/catalog_entry/table_macro_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" +#include "duckdb/catalog/default/default_coordinate_systems.hpp" #include "duckdb/catalog/default/default_functions.hpp" #include "duckdb/catalog/default/default_table_functions.hpp" #include "duckdb/catalog/default/default_types.hpp" @@ -23,6 +25,7 @@ #include "duckdb/main/database.hpp" #include "duckdb/parser/constraints/foreign_key_constraint.hpp" #include "duckdb/parser/parsed_data/alter_table_info.hpp" +#include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" #include "duckdb/parser/parsed_data/create_collation_info.hpp" #include "duckdb/parser/parsed_data/create_copy_function_info.hpp" #include "duckdb/parser/parsed_data/create_index_info.hpp" @@ -75,7 +78,9 @@ DuckSchemaEntry::DuckSchemaEntry(Catalog &catalog, CreateSchemaInfo &info) catalog.IsSystemCatalog() ? make_uniq(catalog, *this) : nullptr), copy_functions(catalog), pragma_functions(catalog), functions(catalog, catalog.IsSystemCatalog() ? make_uniq(catalog, *this) : nullptr), - sequences(catalog), collations(catalog), types(catalog, make_uniq(catalog, *this)) { + sequences(catalog), collations(catalog), types(catalog, make_uniq(catalog, *this)), + coordinate_systems( + catalog, catalog.IsSystemCatalog() ? make_uniq(catalog, *this) : nullptr) { } unique_ptr DuckSchemaEntry::Copy(ClientContext &context) const { @@ -257,6 +262,13 @@ optional_ptr DuckSchemaEntry::CreateCollation(CatalogTransaction t return AddEntry(transaction, std::move(collation), info.on_conflict); } +optional_ptr DuckSchemaEntry::CreateCoordinateSystem(CatalogTransaction transaction, + CreateCoordinateSystemInfo &info) { + auto coordinate_system = make_uniq(catalog, *this, info); + coordinate_system->internal = info.internal; + return AddEntry(transaction, std::move(coordinate_system), info.on_conflict); +} + optional_ptr DuckSchemaEntry::CreateTableFunction(CatalogTransaction transaction, CreateTableFunctionInfo &info) { auto table_function = make_uniq(catalog, *this, info); @@ -388,6 +400,8 @@ CatalogSet &DuckSchemaEntry::GetCatalogSet(CatalogType type) { return sequences; case CatalogType::COLLATION_ENTRY: return collations; + case CatalogType::COORDINATE_SYSTEM_ENTRY: + return coordinate_systems; case CatalogType::TYPE_ENTRY: return types; default: diff --git a/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp b/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp index eda90ac9e..32e39cff2 100644 --- a/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp @@ -53,6 +53,10 @@ DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, Bou // create the physical storage vector column_defs; for (auto &col_def : columns.Physical()) { + if (TypeVisitor::Contains(col_def.Type(), LogicalTypeId::TYPE)) { + throw InvalidInputException("A table cannot be created with a 'TYPE' column"); + } + column_defs.push_back(col_def.Copy()); } storage = make_shared_ptr(catalog.GetAttached(), StorageManager::Get(catalog).GetTableIOManager(&info), @@ -73,18 +77,18 @@ DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, Bou auto column_indexes = unique.GetLogicalIndexes(columns); if (info.indexes.empty()) { auto index_info = GetIndexInfo(constraint_type, false, info.base, i); - storage->AddIndex(columns, column_indexes, constraint_type, index_info); + storage->AddIndex(columns, column_indexes, constraint_type, std::move(index_info)); continue; } // We read the index from an old storage version applying a dummy name. - if (info.indexes[indexes_idx].name.empty()) { + auto index_storage_info = std::move(info.indexes[indexes_idx++]); + if (index_storage_info.name.empty()) { auto name_info = GetIndexInfo(constraint_type, true, info.base, i); - info.indexes[indexes_idx].name = name_info.name; + index_storage_info.name = name_info.name; } - // Now we can add the index. - storage->AddIndex(columns, column_indexes, constraint_type, info.indexes[indexes_idx++]); + storage->AddIndex(columns, column_indexes, constraint_type, std::move(index_storage_info)); continue; } @@ -102,24 +106,30 @@ DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, Bou if (info.indexes.empty()) { auto constraint_type = IndexConstraintType::FOREIGN; auto index_info = GetIndexInfo(constraint_type, false, info.base, i); - storage->AddIndex(columns, column_indexes, constraint_type, index_info); + storage->AddIndex(columns, column_indexes, constraint_type, std::move(index_info)); continue; } // We read the index from an old storage version applying a dummy name. - if (info.indexes[indexes_idx].name.empty()) { + auto index_storage_info = std::move(info.indexes[indexes_idx++]); + if (index_storage_info.name.empty()) { auto name_info = GetIndexInfo(IndexConstraintType::FOREIGN, true, info.base, i); - info.indexes[indexes_idx].name = name_info.name; + index_storage_info.name = name_info.name; } - // Now we can add the index. - storage->AddIndex(columns, column_indexes, IndexConstraintType::FOREIGN, info.indexes[indexes_idx++]); + storage->AddIndex(columns, column_indexes, IndexConstraintType::FOREIGN, std::move(index_storage_info)); } } } - if (!info.indexes.empty()) { - storage->SetIndexStorageInfo(std::move(info.indexes)); + // Move any remaining unused IndexStorageInfos to storage. + // These are non-constraint indexes that are still unbound at this point. + vector remaining_indexes; + while (indexes_idx < info.indexes.size()) { + remaining_indexes.push_back(std::move(info.indexes[indexes_idx++])); + } + if (!remaining_indexes.empty()) { + storage->SetIndexStorageInfo(std::move(remaining_indexes)); } } @@ -242,6 +252,11 @@ unique_ptr DuckTableEntry::AlterEntry(ClientContext &context, Alte throw NotImplementedException("SET PARTITIONED BY is not supported for DuckDB tables"); case AlterTableType::SET_SORTED_BY: throw NotImplementedException("SET SORTED BY is not supported for DuckDB tables"); + case AlterTableType::SET_TABLE_OPTIONS: + throw NotImplementedException("SET () is not supported for DuckDB tables"); + case AlterTableType::RESET_TABLE_OPTIONS: { + throw NotImplementedException("RESET () is not supported for DuckDB tables"); + } default: throw InternalException("Unrecognized alter table type!"); } @@ -359,8 +374,11 @@ unique_ptr DuckTableEntry::AddColumn(ClientContext &context, AddCo for (auto &constraint : constraints) { create_info->constraints.push_back(constraint->Copy()); } + auto binder = Binder::CreateBinder(context); - binder->BindLogicalType(info.new_column.TypeMutable(), &catalog, schema.name); + binder->SetSearchPath(catalog, schema.name); + binder->BindLogicalType(info.new_column.TypeMutable()); + info.new_column.SetOid(columns.LogicalColumnCount()); info.new_column.SetStorageOid(columns.PhysicalColumnCount()); auto col = info.new_column.Copy(); @@ -973,8 +991,10 @@ unique_ptr DuckTableEntry::DropNotNull(ClientContext &context, Dro } unique_ptr DuckTableEntry::ChangeColumnType(ClientContext &context, ChangeColumnTypeInfo &info) { - auto binder = Binder::CreateBinder(context); - binder->BindLogicalType(info.target_type, &catalog, schema.name); + // Bind type + auto type_binder = Binder::CreateBinder(context); + type_binder->SetSearchPath(catalog, schema.name); + type_binder->BindLogicalType(info.target_type); auto change_idx = GetColumnIndex(info.column_name); auto create_info = make_uniq(schema, name); @@ -983,6 +1003,7 @@ unique_ptr DuckTableEntry::ChangeColumnType(ClientContext &context create_info->tags = tags; // Bind the USING expression. + auto binder = Binder::CreateBinder(context); vector bound_columns; AlterBinder expr_binder(*binder, context, *this, bound_columns, info.target_type); auto expression = info.expression->Copy(); diff --git a/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp index e5778ad4c..16cc2627b 100644 --- a/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp @@ -1,7 +1,9 @@ #include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp" + +#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" #include "duckdb/common/vector.hpp" -#include "duckdb/parser/parsed_data/alter_scalar_function_info.hpp" #include "duckdb/main/attached_database.hpp" +#include "duckdb/parser/parsed_data/alter_scalar_function_info.hpp" namespace duckdb { diff --git a/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp index f31a589ee..6922aab5f 100644 --- a/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp @@ -4,16 +4,18 @@ #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" #include "duckdb/common/algorithm.hpp" #include "duckdb/common/exception.hpp" +#include "duckdb/common/extra_type_info.hpp" #include "duckdb/main/database.hpp" #include "duckdb/parser/constraints/list.hpp" +#include "duckdb/parser/expression/cast_expression.hpp" #include "duckdb/parser/parsed_data/create_table_info.hpp" -#include "duckdb/storage/table_storage_info.hpp" -#include "duckdb/planner/operator/logical_update.hpp" -#include "duckdb/planner/operator/logical_get.hpp" +#include "duckdb/planner/binder.hpp" #include "duckdb/planner/constraints/bound_check_constraint.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" +#include "duckdb/planner/operator/logical_get.hpp" #include "duckdb/planner/operator/logical_projection.hpp" -#include "duckdb/common/extra_type_info.hpp" -#include "duckdb/parser/expression/cast_expression.hpp" +#include "duckdb/planner/operator/logical_update.hpp" +#include "duckdb/storage/table_storage_info.hpp" #include @@ -157,10 +159,19 @@ string TableCatalogEntry::ColumnsToSQL(const ColumnList &columns, const vectortype == ExtraTypeInfoType::STRING_TYPE_INFO) { - auto &string_info = extra_type_info->Cast(); - if (!string_info.collation.empty()) { - ss << " COLLATE " + string_info.collation; + if (extra_type_info) { + if (extra_type_info->type == ExtraTypeInfoType::STRING_TYPE_INFO) { + auto &string_info = extra_type_info->Cast(); + if (!string_info.collation.empty()) { + ss << " COLLATE " + string_info.collation; + } + } + if (extra_type_info->type == ExtraTypeInfoType::UNBOUND_TYPE_INFO) { + // TODO + // auto &colllation = UnboundType::GetCollation(column_type); + // if (!colllation.empty()) { + // ss << " COLLATE " + colllation; + //} } } bool not_null = not_null_columns.find(column.Logical()) != not_null_columns.end(); @@ -174,7 +185,6 @@ string TableCatalogEntry::ColumnsToSQL(const ColumnList &columns, const vector(); - D_ASSERT(cast_expr.cast_type.id() == column_type.id()); generated_expression = *cast_expr.child; } ss << " GENERATED ALWAYS AS(" << generated_expression.get().ToString() << ")"; diff --git a/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp index f06ef164e..6ad264ca7 100644 --- a/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp @@ -1,6 +1,8 @@ #include "duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp" -#include "duckdb/parser/parsed_data/alter_table_function_info.hpp" + +#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" #include "duckdb/main/attached_database.hpp" +#include "duckdb/parser/parsed_data/alter_table_function_info.hpp" namespace duckdb { diff --git a/src/duckdb/src/catalog/catalog_entry/view_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/view_catalog_entry.cpp index a02de0cec..89ae13950 100644 --- a/src/duckdb/src/catalog/catalog_entry/view_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/view_catalog_entry.cpp @@ -7,6 +7,8 @@ #include "duckdb/parser/parsed_data/create_view_info.hpp" #include "duckdb/parser/parsed_data/comment_on_column_info.hpp" #include "duckdb/common/limits.hpp" +#include "duckdb/planner/binder.hpp" +#include "duckdb/catalog/catalog.hpp" #include @@ -15,19 +17,27 @@ namespace duckdb { void ViewCatalogEntry::Initialize(CreateViewInfo &info) { query = std::move(info.query); this->aliases = info.aliases; - this->types = info.types; - this->names = info.names; + if (!info.types.empty() && !info.names.empty()) { + bind_state = ViewBindState::BOUND; + view_columns = make_shared_ptr(); + view_columns->types = info.types; + view_columns->names = info.names; + if (info.types.size() != info.names.size()) { + throw InternalException("Error creating view %s - view types / names size mismatch (%d types, %d names)", + name, info.types.size(), info.names.size()); + } + } this->temporary = info.temporary; this->sql = info.sql; this->internal = info.internal; this->dependencies = info.dependencies; this->comment = info.comment; this->tags = info.tags; - this->column_comments = info.column_comments; + this->column_comments = info.column_comments_map; } ViewCatalogEntry::ViewCatalogEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateViewInfo &info) - : StandardEntry(CatalogType::VIEW_ENTRY, schema, catalog, info.view_name) { + : StandardEntry(CatalogType::VIEW_ENTRY, schema, catalog, info.view_name), bind_state(ViewBindState::UNBOUND) { Initialize(info); } @@ -38,13 +48,16 @@ unique_ptr ViewCatalogEntry::GetInfo() const { result->sql = sql; result->query = query ? unique_ptr_cast(query->Copy()) : nullptr; result->aliases = aliases; - result->names = names; - result->types = types; + auto view_columns = GetColumnInfo(); + if (view_columns) { + result->names = view_columns->names; + result->types = view_columns->types; + } result->temporary = temporary; result->dependencies = dependencies; result->comment = comment; result->tags = tags; - result->column_comments = column_comments; + result->column_comments_map = column_comments; return std::move(result); } @@ -56,22 +69,20 @@ unique_ptr ViewCatalogEntry::AlterEntry(ClientContext &context, Al auto &comment_on_column_info = info.Cast(); auto copied_view = Copy(context); - for (idx_t i = 0; i < names.size(); i++) { - const auto &col_name = names[i]; - if (col_name == comment_on_column_info.column_name) { - auto &copied_view_entry = copied_view->Cast(); - - // If vector is empty, we need to initialize it on setting here - if (copied_view_entry.column_comments.empty()) { - copied_view_entry.column_comments = vector(copied_view_entry.types.size()); - } - - copied_view_entry.column_comments[i] = comment_on_column_info.comment_value; - return copied_view; + auto view_columns = GetColumnInfo(); + if (view_columns) { + // if the view is bound - verify the name we are commenting on exists + auto &names = view_columns->names; + auto entry = std::find(names.begin(), names.end(), comment_on_column_info.column_name); + if (entry == names.end()) { + throw BinderException("View \"%s\" does not have a column with name \"%s\"", name, + comment_on_column_info.column_name); } } - throw BinderException("View \"%s\" does not have a column with name \"%s\"", name, - comment_on_column_info.column_name); + // apply the comment to the view + auto &copied_view_entry = copied_view->Cast(); + copied_view_entry.column_comments[comment_on_column_info.column_name] = comment_on_column_info.comment_value; + return copied_view; } if (info.type != AlterType::ALTER_VIEW) { @@ -90,6 +101,61 @@ unique_ptr ViewCatalogEntry::AlterEntry(ClientContext &context, Al } } +shared_ptr ViewCatalogEntry::GetColumnInfo() const { + return view_columns.atomic_load(); +} + +Value ViewCatalogEntry::GetColumnComment(idx_t column_index) { + auto view_columns = GetColumnInfo(); + if (!view_columns) { + throw InternalException("ViewCatalogEntry::GetColumnComment called - but view has not been bound yet"); + } + auto &names = view_columns->names; + if (column_index >= names.size()) { + return Value(); + } + auto &name = names[column_index]; + auto entry = column_comments.find(name); + if (entry != column_comments.end()) { + return entry->second; + } + return Value(); +} + +void ViewCatalogEntry::BindView(ClientContext &context, BindViewAction action) { + if (bind_state == ViewBindState::BINDING && bind_thread == ThreadUtil::GetThreadId()) { + throw InvalidInputException("View \"%s\" was requested to be bound but this thread is already binding that " + "view - this likely means the view was attempted to be bound recursively", + name); + } + lock_guard guard(bind_lock); + if (action == BindViewAction::BIND_IF_UNBOUND && view_columns) { + // already bound + return; + } + bind_state = ViewBindState::BINDING; + bind_thread = ThreadUtil::GetThreadId(); + auto columns = make_shared_ptr(); + Binder::BindView(context, GetQuery(), ParentCatalog().GetName(), ParentSchema().name, nullptr, aliases, + columns->types, columns->names); + view_columns.atomic_store(columns); + bind_state = ViewBindState::BOUND; +} + +void ViewCatalogEntry::UpdateBinding(const vector &types_p, const vector &names_p) { + auto columns = view_columns.atomic_load(); + if (columns && columns->types == types_p && columns->names == names_p) { + // already bound with the current info + return; + } + lock_guard guard(bind_lock); + auto new_columns = make_shared_ptr(); + new_columns->types = types_p; + new_columns->names = names_p; + view_columns.atomic_store(new_columns); + bind_state = ViewBindState::BOUND; +} + string ViewCatalogEntry::ToSQL() const { if (sql.empty()) { //! Return empty sql with view name so pragma view_tables don't complain diff --git a/src/duckdb/src/catalog/catalog_set.cpp b/src/duckdb/src/catalog/catalog_set.cpp index 6e5b17610..5af535016 100644 --- a/src/duckdb/src/catalog/catalog_set.cpp +++ b/src/duckdb/src/catalog/catalog_set.cpp @@ -568,12 +568,17 @@ optional_ptr CatalogSet::CreateDefaultEntry(CatalogTransaction tra // no defaults either: return null return nullptr; } - read_lock.unlock(); + auto unlock = !defaults->LockDuringCreate(); + if (unlock) { + read_lock.unlock(); + } // this catalog set has a default map defined // check if there is a default entry that we can create with this name auto entry = defaults->CreateDefaultEntry(transaction, name); - read_lock.lock(); + if (unlock) { + read_lock.lock(); + } if (!entry) { // no default entry return nullptr; @@ -586,7 +591,9 @@ optional_ptr CatalogSet::CreateDefaultEntry(CatalogTransaction tra // we found a default entry, but failed // this means somebody else created the entry first // just retry? - read_lock.unlock(); + if (unlock) { + read_lock.unlock(); + } return GetEntry(transaction, name); } @@ -657,6 +664,7 @@ void CatalogSet::CreateDefaultEntries(CatalogTransaction transaction, unique_loc if (!defaults || defaults->created_all_entries) { return; } + auto unlock = !defaults->LockDuringCreate(); // this catalog set has a default set defined: auto default_entries = defaults->GetDefaultEntries(); for (auto &default_entry : default_entries) { @@ -664,13 +672,17 @@ void CatalogSet::CreateDefaultEntries(CatalogTransaction transaction, unique_loc if (!entry_value) { // we unlock during the CreateEntry, since it might reference other catalog sets... // specifically for views this can happen since the view will be bound - read_lock.unlock(); + if (unlock) { + read_lock.unlock(); + } auto entry = defaults->CreateDefaultEntry(transaction, default_entry); if (!entry) { throw InternalException("Failed to create default entry for %s", default_entry); } - read_lock.lock(); + if (unlock) { + read_lock.lock(); + } CreateCommittedEntry(std::move(entry)); } } diff --git a/src/duckdb/src/catalog/default/default_coordinate_systems.cpp b/src/duckdb/src/catalog/default/default_coordinate_systems.cpp new file mode 100644 index 000000000..759c24e5f --- /dev/null +++ b/src/duckdb/src/catalog/default/default_coordinate_systems.cpp @@ -0,0 +1,77 @@ +#include "duckdb/parser/parsed_data/create_coordinate_system_info.hpp" +#include "duckdb/catalog/default/default_coordinate_systems.hpp" +#include "duckdb/catalog/catalog_entry/coordinate_system_catalog_entry.hpp" +#include "duckdb/common/array.hpp" + +namespace duckdb { +class CoordinateSystemCatalogEntry; + +namespace { + +struct DefaultCoordinateReferenceSystem { + const char *name; + const char *auth_code; + const char *srid; + const char *wkt2_2019; + const char *projjson; +}; + +using builtin_crs_array = std::array; + +// CRS84 (WGS84) +const auto OGC_CRS84_WKT2_2019 = + R"WKT_LITERAL(GEOGCRS["WGS 84 (CRS84)",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],MEMBER["World Geodetic System 1984 (G2296)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic longitude (Lon)",east,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic latitude (Lat)",north,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Not known."],AREA["World."],BBOX[-90,-180,90,180]],ID["OGC","CRS84"]])WKT_LITERAL"; + +const auto OGC_CRS84_PROJJSON = + R"JSON_LITERAL({"$schema":"https://proj.org/schemas/v0.7/projjson.schema.json","type":"GeographicCRS","name":"WGS 84 (CRS84)","datum_ensemble":{"name":"World Geodetic System 1984 ensemble","members":[{"name":"World Geodetic System 1984 (Transit)","id":{"authority":"EPSG","code":1166}},{"name":"World Geodetic System 1984 (G730)","id":{"authority":"EPSG","code":1152}},{"name":"World Geodetic System 1984 (G873)","id":{"authority":"EPSG","code":1153}},{"name":"World Geodetic System 1984 (G1150)","id":{"authority":"EPSG","code":1154}},{"name":"World Geodetic System 1984 (G1674)","id":{"authority":"EPSG","code":1155}},{"name":"World Geodetic System 1984 (G1762)","id":{"authority":"EPSG","code":1156}},{"name":"World Geodetic System 1984 (G2139)","id":{"authority":"EPSG","code":1309}},{"name":"World Geodetic System 1984 (G2296)","id":{"authority":"EPSG","code":1383}}],"ellipsoid":{"name":"WGS 84","semi_major_axis":6378137,"inverse_flattening":298.257223563},"accuracy":"2.0","id":{"authority":"EPSG","code":6326}},"coordinate_system":{"subtype":"ellipsoidal","axis":[{"name":"Geodetic longitude","abbreviation":"Lon","direction":"east","unit":"degree"},{"name":"Geodetic latitude","abbreviation":"Lat","direction":"north","unit":"degree"}]},"scope":"Not known.","area":"World.","bbox":{"south_latitude":-90,"west_longitude":-180,"north_latitude":90,"east_longitude":180},"id":{"authority":"OGC","code":"CRS84"}})JSON_LITERAL"; + +// CRS83 (NAD83) +const auto OGC_CRS83_WKT2_2019 = + R"WKT_LITERAL(GEOGCRS["NAD83 (CRS83)",DATUM["North American Datum 1983",ELLIPSOID["GRS 1980",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic longitude (Lon)",east,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic latitude (Lat)",north,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Not known."],AREA["North America - onshore and offshore: Canada - Alberta; British Columbia; Manitoba; New Brunswick; Newfoundland and Labrador; Northwest Territories; Nova Scotia; Nunavut; Ontario; Prince Edward Island; Quebec; Saskatchewan; Yukon. Puerto Rico. United States (USA) - Alabama; Alaska; Arizona; Arkansas; California; Colorado; Connecticut; Delaware; Florida; Georgia; Hawaii; Idaho; Illinois; Indiana; Iowa; Kansas; Kentucky; Louisiana; Maine; Maryland; Massachusetts; Michigan; Minnesota; Mississippi; Missouri; Montana; Nebraska; Nevada; New Hampshire; New Jersey; New Mexico; New York; North Carolina; North Dakota; Ohio; Oklahoma; Oregon; Pennsylvania; Rhode Island; South Carolina; South Dakota; Tennessee; Texas; Utah; Vermont; Virginia; Washington; West Virginia; Wisconsin; Wyoming. US Virgin Islands. British Virgin Islands."],BBOX[14.92,167.65,86.45,-40.73]],ID["OGC","CRS83"]])WKT_LITERAL"; + +const auto OGC_CRS83_PROJJSON = + R"JSON_LITERAL({"$schema":"https://proj.org/schemas/v0.7/projjson.schema.json","type":"GeographicCRS","name":"NAD83 (CRS83)","datum":{"type":"GeodeticReferenceFrame","name":"North American Datum 1983","ellipsoid":{"name":"GRS 1980","semi_major_axis":6378137,"inverse_flattening":298.257222101}},"coordinate_system":{"subtype":"ellipsoidal","axis":[{"name":"Geodetic longitude","abbreviation":"Lon","direction":"east","unit":"degree"},{"name":"Geodetic latitude","abbreviation":"Lat","direction":"north","unit":"degree"}]},"scope":"Not known.","area":"North America - onshore and offshore: Canada - Alberta; British Columbia; Manitoba; New Brunswick; Newfoundland and Labrador; Northwest Territories; Nova Scotia; Nunavut; Ontario; Prince Edward Island; Quebec; Saskatchewan; Yukon. Puerto Rico. United States (USA) - Alabama; Alaska; Arizona; Arkansas; California; Colorado; Connecticut; Delaware; Florida; Georgia; Hawaii; Idaho; Illinois; Indiana; Iowa; Kansas; Kentucky; Louisiana; Maine; Maryland; Massachusetts; Michigan; Minnesota; Mississippi; Missouri; Montana; Nebraska; Nevada; New Hampshire; New Jersey; New Mexico; New York; North Carolina; North Dakota; Ohio; Oklahoma; Oregon; Pennsylvania; Rhode Island; South Carolina; South Dakota; Tennessee; Texas; Utah; Vermont; Virginia; Washington; West Virginia; Wisconsin; Wyoming. US Virgin Islands. British Virgin Islands.","bbox":{"south_latitude":14.92,"west_longitude":167.65,"north_latitude":86.45,"east_longitude":-40.73},"id":{"authority":"OGC","code":"CRS83"}})JSON_LITERAL"; + +const builtin_crs_array DEFAULT_CRS_DEFINITIONS = {{ + DefaultCoordinateReferenceSystem {"OGC:CRS84", "OGC", "CRS84", OGC_CRS84_WKT2_2019, OGC_CRS84_PROJJSON}, + DefaultCoordinateReferenceSystem {"OGC:CRS83", "OGC", "CRS83", OGC_CRS83_WKT2_2019, OGC_CRS83_PROJJSON}, +}}; + +} // namespace + +DefaultCoordinateSystemGenerator::DefaultCoordinateSystemGenerator(Catalog &catalog, SchemaCatalogEntry &schema) + : DefaultGenerator(catalog), schema(schema) { +} + +unique_ptr DefaultCoordinateSystemGenerator::CreateDefaultEntry(ClientContext &context, + const string &entry_name) { + if (schema.name != DEFAULT_SCHEMA) { + return nullptr; + } + + for (const auto &crs_definition : DEFAULT_CRS_DEFINITIONS) { + if (entry_name == crs_definition.name) { + CreateCoordinateSystemInfo info(crs_definition.name, crs_definition.auth_code, crs_definition.srid, + crs_definition.projjson, crs_definition.wkt2_2019); + + auto result = make_uniq(catalog, schema, info); + return std::move(result); + } + } + + return nullptr; +} + +vector DefaultCoordinateSystemGenerator::GetDefaultEntries() { + if (schema.name != DEFAULT_SCHEMA) { + return {}; + } + + vector entries; + for (const auto &crs_definition : DEFAULT_CRS_DEFINITIONS) { + entries.push_back(crs_definition.name); + } + return entries; +} + +} // namespace duckdb diff --git a/src/duckdb/src/catalog/default/default_functions.cpp b/src/duckdb/src/catalog/default/default_functions.cpp index 37d5e0286..ec40b5bbc 100644 --- a/src/duckdb/src/catalog/default/default_functions.cpp +++ b/src/duckdb/src/catalog/default/default_functions.cpp @@ -62,7 +62,7 @@ static const DefaultMacro internal_macros[] = { {"pg_catalog", "pg_get_expr", {"pg_node_tree", "relation_oid", nullptr}, {{nullptr, nullptr}}, "pg_node_tree"}, {"pg_catalog", "format_pg_type", {"logical_type", "type_name", nullptr}, {{nullptr, nullptr}}, "case upper(logical_type) when 'FLOAT' then 'float4' when 'DOUBLE' then 'float8' when 'DECIMAL' then 'numeric' when 'ENUM' then lower(type_name) when 'VARCHAR' then 'varchar' when 'BLOB' then 'bytea' when 'TIMESTAMP' then 'timestamp' when 'TIME' then 'time' when 'TIMESTAMP WITH TIME ZONE' then 'timestamptz' when 'TIME WITH TIME ZONE' then 'timetz' when 'SMALLINT' then 'int2' when 'INTEGER' then 'int4' when 'BIGINT' then 'int8' when 'BOOLEAN' then 'bool' else lower(logical_type) end"}, {"pg_catalog", "format_type", {"type_oid", "typemod", nullptr}, {{nullptr, nullptr}}, "(select format_pg_type(logical_type, type_name) from duckdb_types() t where t.type_oid=type_oid) || case when typemod>0 then concat('(', typemod//1000, ',', typemod%1000, ')') else '' end"}, - {"pg_catalog", "map_to_pg_oid", {"type_name", nullptr}, {{nullptr, nullptr}}, "case type_name when 'bool' then 16 when 'int16' then 21 when 'int' then 23 when 'bigint' then 20 when 'date' then 1082 when 'time' then 1083 when 'datetime' then 1114 when 'dec' then 1700 when 'float' then 700 when 'double' then 701 when 'bpchar' then 1043 when 'binary' then 17 when 'interval' then 1186 when 'timestamptz' then 1184 when 'timetz' then 1266 when 'bit' then 1560 when 'guid' then 2950 else null end"}, // map duckdb_oid to pg_oid. If no corresponding type, return null + {"pg_catalog", "map_to_pg_oid", {"type_name", nullptr}, {{nullptr, nullptr}}, "case type_name when 'bool' then 16 when 'int16' then 21 when 'int' then 23 when 'bigint' then 20 when 'date' then 1082 when 'time' then 1083 when 'datetime' then 1114 when 'dec' then 1700 when 'float' then 700 when 'double' then 701 when 'bpchar' then 1043 when 'binary' then 17 when 'interval' then 1186 when 'timestamptz' then 1184 when 'timestamp with time zone' then 1184 when 'timetz' then 1266 when 'time with time zone' then 1266 when 'bit' then 1560 when 'guid' then 2950 else null end"}, // map duckdb_oid to pg_oid. If no corresponding type, return null {"pg_catalog", "pg_has_role", {"user", "role", "privilege", nullptr}, {{nullptr, nullptr}}, "true"}, //boolean //does user have privilege for role {"pg_catalog", "pg_has_role", {"role", "privilege", nullptr}, {{nullptr, nullptr}}, "true"}, //boolean //does current user have privilege for role diff --git a/src/duckdb/src/catalog/default/default_types.cpp b/src/duckdb/src/catalog/default/default_types.cpp index 23edac049..a2c8f5abe 100644 --- a/src/duckdb/src/catalog/default/default_types.cpp +++ b/src/duckdb/src/catalog/default/default_types.cpp @@ -4,10 +4,560 @@ #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/parsed_data/create_type_info.hpp" -#include "duckdb/catalog/default/builtin_types/types.hpp" +#include "duckdb/common/types/decimal.hpp" +#include "duckdb/common/exception/binder_exception.hpp" +#include "duckdb/common/array.hpp" +#include "duckdb/common/types/geometry_crs.hpp" +#include "duckdb/main/settings.hpp" +#include "duckdb/planner/expression_binder.hpp" namespace duckdb { +namespace { + +//---------------------------------------------------------------------------------------------------------------------- +// DECIMAL Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindDecimalType(BindLogicalTypeInput &input) { + auto &modifiers = input.modifiers; + + uint8_t width = 18; + uint8_t scale = 3; + + if (!modifiers.empty()) { + auto width_value = modifiers[0].GetValue(); + if (width_value.IsNull()) { + throw BinderException("DECIMAL type width cannot be NULL"); + } + if (width_value.DefaultTryCastAs(LogicalTypeId::UTINYINT)) { + width = width_value.GetValueUnsafe(); + scale = 0; // reset scale to 0 if only width is provided + } else { + throw BinderException("DECIMAL type width must be between 1 and %d", Decimal::MAX_WIDTH_DECIMAL); + } + } + + if (modifiers.size() > 1) { + auto scale_value = modifiers[1].GetValue(); + if (scale_value.IsNull()) { + throw BinderException("DECIMAL type scale cannot be NULL"); + } + if (scale_value.DefaultTryCastAs(LogicalTypeId::UTINYINT)) { + scale = scale_value.GetValueUnsafe(); + } else { + throw BinderException("DECIMAL type scale must be between 0 and %d", Decimal::MAX_WIDTH_DECIMAL - 1); + } + } + + if (modifiers.size() > 2) { + throw BinderException("DECIMAL type can take at most two type modifiers, width and scale"); + } + + if (width < 1 || width > Decimal::MAX_WIDTH_DECIMAL) { + throw BinderException("DECIMAL type width must be between 1 and %d", Decimal::MAX_WIDTH_DECIMAL); + } + + if (scale > width) { + throw BinderException("DECIMAL type scale cannot be greater than width"); + } + return LogicalType::DECIMAL(width, scale); +} + +//---------------------------------------------------------------------------------------------------------------------- +// TIMESTAMP Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindTimestampType(BindLogicalTypeInput &input) { + auto &modifiers = input.modifiers; + + if (modifiers.empty()) { + return LogicalType::TIMESTAMP; + } + + if (modifiers.size() > 1) { + throw BinderException("TIMESTAMP type takes at most one type modifier"); + } + + auto precision_value = modifiers[0].GetValue(); + if (precision_value.IsNull()) { + throw BinderException("TIMESTAMP type precision cannot be NULL"); + } + uint8_t precision; + if (precision_value.DefaultTryCastAs(LogicalTypeId::UTINYINT)) { + precision = precision_value.GetValueUnsafe(); + } else { + throw BinderException("TIMESTAMP type precision must be between 0 and 9"); + } + + if (precision > 9) { + throw BinderException("TIMESTAMP only supports until nano-second precision (9)"); + } + if (precision == 0) { + return LogicalType::TIMESTAMP_S; + } + if (precision <= 3) { + return LogicalType::TIMESTAMP_MS; + } + if (precision <= 6) { + return LogicalType::TIMESTAMP; + } + return LogicalType::TIMESTAMP_NS; +} + +//---------------------------------------------------------------------------------------------------------------------- +// VARCHAR Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindVarcharType(BindLogicalTypeInput &input) { + // Varchar type can have a single modifier indicating the length, but we ignore it for now + auto &modifiers = input.modifiers; + + if (!modifiers.empty() && modifiers.size() <= 2) { + for (auto &mod : modifiers) { + if (mod.IsNamed("collation") && mod.GetType() == LogicalType::VARCHAR && mod.IsNotNull()) { + // Ignore all other modifiers and return collation type + auto collation = StringValue::Get(mod.GetValue()); + + if (!input.context) { + throw BinderException("Cannot bind varchar with collation without a connection"); + } + + // Ensure this is a valid collation + ExpressionBinder::TestCollation(*input.context, collation); + + return LogicalType::VARCHAR_COLLATION(collation); + } + } + } + + if (modifiers.size() > 1) { + throw BinderException("VARCHAR type takes at most one type modifier"); + } + + return LogicalType::VARCHAR; +} + +//---------------------------------------------------------------------------------------------------------------------- +// BIT Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindBitType(BindLogicalTypeInput &input) { + // BIT type can have a single modifier indicating the length, but we ignore it for now + auto &args = input.modifiers; + if (args.size() > 1) { + throw BinderException("BIT type takes at most one type modifier"); + } + return LogicalType::BIT; +} + +//---------------------------------------------------------------------------------------------------------------------- +// INTERVAL Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindIntervalType(BindLogicalTypeInput &input) { + // Interval type can have a single modifier indicating the leading field, but we ignore it for now + auto &modifiers = input.modifiers; + if (modifiers.size() > 1) { + throw BinderException("INTERVAL type takes at most one type modifier"); + } + return LogicalType::INTERVAL; +} + +//---------------------------------------------------------------------------------------------------------------------- +// ENUM Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindEnumType(BindLogicalTypeInput &input) { + auto &arguments = input.modifiers; + + if (arguments.empty()) { + throw BinderException("ENUM type requires at least one argument"); + } + + Vector enum_vector(LogicalType::VARCHAR, NumericCast(arguments.size())); + auto string_data = FlatVector::GetData(enum_vector); + + for (idx_t arg_idx = 0; arg_idx < arguments.size(); arg_idx++) { + auto &arg = arguments[arg_idx]; + if (arg.HasName()) { + throw BinderException("ENUM type arguments cannot have names (argument %d has name \"%s\")", arg_idx + 1, + arg.GetName()); + } + + if (arg.GetValue().type() != LogicalTypeId::VARCHAR) { + throw BinderException("ENUM type requires a set of VARCHAR arguments"); + } + + if (arg.GetValue().IsNull()) { + throw BinderException("ENUM type arguments cannot be NULL (argument %d is NULL)", arg_idx + 1); + } + + string_data[arg_idx] = StringVector::AddString(enum_vector, StringValue::Get(arg.GetValue())); + } + + return LogicalType::ENUM(enum_vector, NumericCast(arguments.size())); +} + +//---------------------------------------------------------------------------------------------------------------------- +// LIST Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindListType(BindLogicalTypeInput &input) { + auto &arguments = input.modifiers; + if (arguments.size() != 1) { + throw BinderException("LIST type requires exactly one type modifier"); + } + auto &child_val = arguments[0].GetValue(); + if (child_val.IsNull()) { + throw BinderException("LIST type modifier cannot be NULL"); + } + if (child_val.type() != LogicalTypeId::TYPE) { + throw BinderException("LIST type modifier must be a type, but got %s", child_val.ToString()); + } + + auto child_type = TypeValue::GetType(arguments[0].GetValue()); + return LogicalType::LIST(child_type); +} + +//---------------------------------------------------------------------------------------------------------------------- +// ARRAY Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindArrayType(BindLogicalTypeInput &input) { + auto &arguments = input.modifiers; + if (arguments.size() != 2) { + throw BinderException("ARRAY type requires exactly two type modifiers"); + } + auto &elem_val = arguments[0].GetValue(); + if (elem_val.IsNull()) { + throw BinderException("ARRAY type modifier cannot be NULL"); + } + if (elem_val.type() != LogicalTypeId::TYPE) { + throw BinderException("ARRAY type modifier must be a type, but got %s", elem_val.ToString()); + } + + auto size_val = arguments[1].GetValue(); + if (size_val.IsNull()) { + throw BinderException("ARRAY type size modifier cannot be NULL"); + } + if (!size_val.type().IsIntegral()) { + throw BinderException("ARRAY type size modifier must be an integral type"); + } + if (!size_val.DefaultTryCastAs(LogicalTypeId::BIGINT)) { + throw BinderException("ARRAY type size modifier must be a BIGINT"); + } + + auto array_size = size_val.GetValueUnsafe(); + + if (array_size < 1) { + throw BinderException("ARRAY type size must be at least 1"); + } + if (array_size > static_cast(ArrayType::MAX_ARRAY_SIZE)) { + throw BinderException("ARRAY type size must be at most %d", ArrayType::MAX_ARRAY_SIZE); + } + + auto child_type = TypeValue::GetType(arguments[0].GetValue()); + return LogicalType::ARRAY(child_type, UnsafeNumericCast(array_size)); +} + +//---------------------------------------------------------------------------------------------------------------------- +// STRUCT Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindStructType(BindLogicalTypeInput &input) { + auto &arguments = input.modifiers; + + if (arguments.empty()) { + throw BinderException("STRUCT type requires at least one child type"); + } + + auto all_name = true; + auto all_anon = true; + for (auto &arg : arguments) { + if (arg.HasName()) { + all_anon = false; + } else { + all_name = false; + } + + // Also check if all arguments are types + if (arg.GetValue().type() != LogicalTypeId::TYPE) { + throw BinderException("STRUCT type arguments must be types"); + } + + // And not null! + if (arg.GetValue().IsNull()) { + throw BinderException("STRUCT type arguments cannot be NULL"); + } + } + + if (!all_name && !all_anon) { + throw BinderException("STRUCT type arguments must either all have names or all be anonymous"); + } + + if (all_anon) { + // Unnamed struct case + child_list_t children; + for (auto &arg : arguments) { + children.emplace_back("", TypeValue::GetType(arg.GetValue())); + } + return LogicalType::STRUCT(std::move(children)); + } + + // Named struct case + D_ASSERT(all_name); + child_list_t children; + case_insensitive_set_t name_collision_set; + + for (auto &arg : arguments) { + auto &child_name = arg.GetName(); + if (name_collision_set.find(child_name) != name_collision_set.end()) { + throw BinderException("Duplicate STRUCT type argument name \"%s\"", child_name); + } + name_collision_set.insert(child_name); + children.emplace_back(child_name, TypeValue::GetType(arg.GetValue())); + } + + return LogicalType::STRUCT(std::move(children)); +} + +//---------------------------------------------------------------------------------------------------------------------- +// MAP Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindMapType(BindLogicalTypeInput &input) { + auto &arguments = input.modifiers; + + if (arguments.size() != 2) { + throw BinderException("MAP type requires exactly two type modifiers: key type and value type"); + } + + auto &key_val = arguments[0].GetValue(); + auto &val_val = arguments[1].GetValue(); + + if (key_val.type() != LogicalTypeId::TYPE || val_val.type() != LogicalTypeId::TYPE) { + throw BinderException("MAP type modifiers must be types"); + } + if (key_val.IsNull()) { + throw BinderException("MAP type key type modifier cannot be NULL"); + } + if (val_val.IsNull()) { + throw BinderException("MAP type value type modifier cannot be NULL"); + } + + auto key_type = TypeValue::GetType(arguments[0].GetValue()); + auto val_type = TypeValue::GetType(arguments[1].GetValue()); + + return LogicalType::MAP(std::move(key_type), std::move(val_type)); +} + +//---------------------------------------------------------------------------------------------------------------------- +// UNION Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindUnionType(BindLogicalTypeInput &input) { + auto &arguments = input.modifiers; + + if (arguments.empty()) { + throw BinderException("UNION type requires at least one type modifier"); + } + + if (arguments.size() > UnionType::MAX_UNION_MEMBERS) { + throw BinderException("UNION type supports at most %d type modifiers", UnionType::MAX_UNION_MEMBERS); + } + + child_list_t children; + case_insensitive_set_t name_collision_set; + + for (auto &arg : arguments) { + if (!arg.HasName()) { + throw BinderException("UNION type modifiers must have names"); + } + if (arg.GetValue().type() != LogicalTypeId::TYPE) { + throw BinderException("UNION type modifiers must be types"); + } + if (arg.GetValue().IsNull()) { + throw BinderException("UNION type modifiers cannot be NULL"); + } + + auto &entry_name = arg.GetName(); + auto entry_type = TypeValue::GetType(arg.GetValue()); + + if (name_collision_set.find(entry_name) != name_collision_set.end()) { + throw BinderException("Duplicate UNION type member name \"%s\"", entry_name); + } + + name_collision_set.insert(entry_name); + children.emplace_back(entry_name, entry_type); + } + + return LogicalType::UNION(std::move(children)); +} + +//---------------------------------------------------------------------------------------------------------------------- +// VARIANT Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindVariantType(BindLogicalTypeInput &input) { + // We need this function to make sure we always create a VARIANT type with ExtraTypeInfo + auto &arguments = input.modifiers; + + if (!arguments.empty()) { + throw BinderException("Type 'VARIANT' does not take any type parameters"); + } + return LogicalType::VARIANT(); +} + +//---------------------------------------------------------------------------------------------------------------------- +// GEOMETRY Type +//---------------------------------------------------------------------------------------------------------------------- +LogicalType BindGeometryType(BindLogicalTypeInput &input) { + auto &arguments = input.modifiers; + + if (arguments.empty()) { + return LogicalType::GEOMETRY(); + } + + if (arguments.size() > 1) { + throw BinderException( + "GEOMETRY type takes a single optional type modifier with a coordinate system definition"); + } + + const auto &crs_value = arguments[0].GetValue(); + + // Don't do any casting here - only accept string type directly + if (crs_value.type() != LogicalTypeId::VARCHAR) { + throw BinderException("GEOMETRY type modifier must be a string with a coordinate system definition"); + } + if (crs_value.IsNull()) { + throw BinderException("GEOMETRY type modifier cannot be NULL"); + } + + // FIXME: Use extension/ClientContext to expand incomplete/shorthand CRS definitions + auto &crs = StringValue::Get(crs_value); + + if (!input.context) { + throw BinderException("Cannot create GEOMETRY type with coordinate system without a connection"); + } + + const auto crs_result = CoordinateReferenceSystem::TryIdentify(*input.context, crs); + if (!crs_result) { + if (Settings::Get(*input.context)) { + // Ignored by user configuration - return generic GEOMETRY type + return LogicalType::GEOMETRY(); + } + + throw BinderException( + "Encountered unrecognized coordinate system '%s' when trying to create GEOMETRY type\n" + "The coordinate system definition may be incomplete or invalid. Your options are as follows:\n" + "* Load an extension that can identify this coordinate system\n" + "* Provide a full coordinate system definition in e.g. \"PROJJSON\" or \"WKT2\" format\n" + "* Set the 'ignore_unknown_crs' configuration option to drop the coordinate system from the resulting " + "geometry type and make this error go away", + crs); + } + + return LogicalType::GEOMETRY(crs_result->GetDefinition()); +} + +//---------------------------------------------------------------------------------------------------------------------- +// All Types +//---------------------------------------------------------------------------------------------------------------------- + +struct DefaultType { + const char *name; + LogicalTypeId type; + bind_logical_type_function_t bind_function; +}; + +using builtin_type_array = std::array; + +const builtin_type_array BUILTIN_TYPES = {{{"decimal", LogicalTypeId::DECIMAL, BindDecimalType}, + {"dec", LogicalTypeId::DECIMAL, BindDecimalType}, + {"numeric", LogicalTypeId::DECIMAL, BindDecimalType}, + {"time", LogicalTypeId::TIME, nullptr}, + {"time_ns", LogicalTypeId::TIME_NS, nullptr}, + {"date", LogicalTypeId::DATE, nullptr}, + {"timestamp", LogicalTypeId::TIMESTAMP, BindTimestampType}, + {"datetime", LogicalTypeId::TIMESTAMP, BindTimestampType}, + {"timestamp_us", LogicalTypeId::TIMESTAMP, nullptr}, + {"timestamp_ms", LogicalTypeId::TIMESTAMP_MS, nullptr}, + {"timestamp_ns", LogicalTypeId::TIMESTAMP_NS, nullptr}, + {"timestamp_s", LogicalTypeId::TIMESTAMP_SEC, nullptr}, + {"timestamptz", LogicalTypeId::TIMESTAMP_TZ, nullptr}, + {"timestamp with time zone", LogicalTypeId::TIMESTAMP_TZ, nullptr}, + {"timetz", LogicalTypeId::TIME_TZ, nullptr}, + {"time with time zone", LogicalTypeId::TIME_TZ, nullptr}, + {"interval", LogicalTypeId::INTERVAL, BindIntervalType}, + {"varchar", LogicalTypeId::VARCHAR, BindVarcharType}, + {"bpchar", LogicalTypeId::VARCHAR, BindVarcharType}, + {"string", LogicalTypeId::VARCHAR, BindVarcharType}, + {"char", LogicalTypeId::VARCHAR, BindVarcharType}, + {"nvarchar", LogicalTypeId::VARCHAR, BindVarcharType}, + {"text", LogicalTypeId::VARCHAR, BindVarcharType}, + {"blob", LogicalTypeId::BLOB, nullptr}, + {"bytea", LogicalTypeId::BLOB, nullptr}, + {"varbinary", LogicalTypeId::BLOB, nullptr}, + {"binary", LogicalTypeId::BLOB, nullptr}, + {"hugeint", LogicalTypeId::HUGEINT, nullptr}, + {"int128", LogicalTypeId::HUGEINT, nullptr}, + {"uhugeint", LogicalTypeId::UHUGEINT, nullptr}, + {"uint128", LogicalTypeId::UHUGEINT, nullptr}, + {"bigint", LogicalTypeId::BIGINT, nullptr}, + {"oid", LogicalTypeId::BIGINT, nullptr}, + {"long", LogicalTypeId::BIGINT, nullptr}, + {"int8", LogicalTypeId::BIGINT, nullptr}, + {"int64", LogicalTypeId::BIGINT, nullptr}, + {"ubigint", LogicalTypeId::UBIGINT, nullptr}, + {"uint64", LogicalTypeId::UBIGINT, nullptr}, + {"integer", LogicalTypeId::INTEGER, nullptr}, + {"int", LogicalTypeId::INTEGER, nullptr}, + {"int4", LogicalTypeId::INTEGER, nullptr}, + {"signed", LogicalTypeId::INTEGER, nullptr}, + {"integral", LogicalTypeId::INTEGER, nullptr}, + {"int32", LogicalTypeId::INTEGER, nullptr}, + {"uinteger", LogicalTypeId::UINTEGER, nullptr}, + {"uint32", LogicalTypeId::UINTEGER, nullptr}, + {"smallint", LogicalTypeId::SMALLINT, nullptr}, + {"int2", LogicalTypeId::SMALLINT, nullptr}, + {"short", LogicalTypeId::SMALLINT, nullptr}, + {"int16", LogicalTypeId::SMALLINT, nullptr}, + {"usmallint", LogicalTypeId::USMALLINT, nullptr}, + {"uint16", LogicalTypeId::USMALLINT, nullptr}, + {"tinyint", LogicalTypeId::TINYINT, nullptr}, + {"int1", LogicalTypeId::TINYINT, nullptr}, + {"utinyint", LogicalTypeId::UTINYINT, nullptr}, + {"uint8", LogicalTypeId::UTINYINT, nullptr}, + {"struct", LogicalTypeId::STRUCT, BindStructType}, + {"row", LogicalTypeId::STRUCT, BindStructType}, + {"list", LogicalTypeId::LIST, BindListType}, + {"array", LogicalTypeId::ARRAY, BindArrayType}, + {"map", LogicalTypeId::MAP, BindMapType}, + {"union", LogicalTypeId::UNION, BindUnionType}, + {"bit", LogicalTypeId::BIT, BindBitType}, + {"bitstring", LogicalTypeId::BIT, BindBitType}, + {"variant", LogicalTypeId::VARIANT, BindVariantType}, + {"bignum", LogicalTypeId::BIGNUM, nullptr}, + {"varint", LogicalTypeId::BIGNUM, nullptr}, + {"boolean", LogicalTypeId::BOOLEAN, nullptr}, + {"bool", LogicalTypeId::BOOLEAN, nullptr}, + {"logical", LogicalTypeId::BOOLEAN, nullptr}, + {"uuid", LogicalTypeId::UUID, nullptr}, + {"guid", LogicalTypeId::UUID, nullptr}, + {"enum", LogicalTypeId::ENUM, BindEnumType}, + {"null", LogicalTypeId::SQLNULL, nullptr}, + {"float", LogicalTypeId::FLOAT, nullptr}, + {"real", LogicalTypeId::FLOAT, nullptr}, + {"float4", LogicalTypeId::FLOAT, nullptr}, + {"double", LogicalTypeId::DOUBLE, nullptr}, + {"float8", LogicalTypeId::DOUBLE, nullptr}, + {"geometry", LogicalTypeId::GEOMETRY, BindGeometryType}, + {"type", LogicalTypeId::TYPE, nullptr}}}; + +optional_ptr TryGetDefaultTypeEntry(const string &name) { + auto &internal_types = BUILTIN_TYPES; + for (auto &type : internal_types) { + if (StringUtil::CIEquals(name, type.name)) { + return &type; + } + } + return nullptr; +} + +} // namespace + +//---------------------------------------------------------------------------------------------------------------------- +// Default Type Generator +//---------------------------------------------------------------------------------------------------------------------- LogicalTypeId DefaultTypeGenerator::GetDefaultType(const string &name) { auto &internal_types = BUILTIN_TYPES; for (auto &type : internal_types) { @@ -18,6 +568,29 @@ LogicalTypeId DefaultTypeGenerator::GetDefaultType(const string &name) { return LogicalType::INVALID; } +LogicalType DefaultTypeGenerator::TryDefaultBind(const string &name, const vector> ¶ms) { + auto entry = TryGetDefaultTypeEntry(name); + if (!entry) { + return LogicalTypeId::INVALID; + } + + if (!entry->bind_function) { + if (params.empty()) { + return LogicalType(entry->type); + } else { + throw InvalidInputException("Type '%s' does not take any type parameters", name); + } + } + + vector args; + for (auto ¶m : params) { + args.emplace_back(param.first, param.second); + } + + BindLogicalTypeInput input {nullptr, LogicalType(entry->type), args}; + return entry->bind_function(input); +} + DefaultTypeGenerator::DefaultTypeGenerator(Catalog &catalog, SchemaCatalogEntry &schema) : DefaultGenerator(catalog), schema(schema) { } @@ -26,15 +599,16 @@ unique_ptr DefaultTypeGenerator::CreateDefaultEntry(ClientContext if (schema.name != DEFAULT_SCHEMA) { return nullptr; } - auto type_id = GetDefaultType(entry_name); - if (type_id == LogicalTypeId::INVALID) { + auto entry = TryGetDefaultTypeEntry(entry_name); + if (!entry || entry->type == LogicalTypeId::INVALID) { return nullptr; } CreateTypeInfo info; info.name = entry_name; - info.type = LogicalType(type_id); + info.type = LogicalType(entry->type); info.internal = true; info.temporary = true; + info.bind_function = entry->bind_function; return make_uniq_base(catalog, schema, info); } diff --git a/src/duckdb/src/catalog/default/default_views.cpp b/src/duckdb/src/catalog/default/default_views.cpp index 023b6f800..f2edfdaba 100644 --- a/src/duckdb/src/catalog/default/default_views.cpp +++ b/src/duckdb/src/catalog/default/default_views.cpp @@ -53,7 +53,7 @@ static const DefaultView internal_views[] = { {"information_schema", "tables", "SELECT database_name table_catalog, schema_name table_schema, table_name, CASE WHEN temporary THEN 'LOCAL TEMPORARY' ELSE 'BASE TABLE' END table_type, NULL::VARCHAR self_referencing_column_name, NULL::VARCHAR reference_generation, NULL::VARCHAR user_defined_type_catalog, NULL::VARCHAR user_defined_type_schema, NULL::VARCHAR user_defined_type_name, 'YES' is_insertable_into, 'NO' is_typed, CASE WHEN temporary THEN 'PRESERVE' ELSE NULL END commit_action, comment AS TABLE_COMMENT FROM duckdb_tables() UNION ALL SELECT database_name table_catalog, schema_name table_schema, view_name table_name, 'VIEW' table_type, NULL self_referencing_column_name, NULL reference_generation, NULL user_defined_type_catalog, NULL user_defined_type_schema, NULL user_defined_type_name, 'NO' is_insertable_into, 'NO' is_typed, NULL commit_action, comment AS TABLE_COMMENT FROM duckdb_views;"}, {"information_schema", "character_sets", "SELECT NULL::VARCHAR character_set_catalog, NULL::VARCHAR character_set_schema, 'UTF8' character_set_name, 'UCS' character_repertoire, 'UTF8' form_of_use, current_database() default_collate_catalog, 'pg_catalog' default_collate_schema, 'ucs_basic' default_collate_name;"}, {"information_schema", "referential_constraints", "SELECT f.database_name constraint_catalog, f.schema_name constraint_schema, f.constraint_name constraint_name, c.database_name unique_constraint_catalog, c.schema_name unique_constraint_schema, c.constraint_name unique_constraint_name, 'NONE' match_option, 'NO ACTION' update_rule, 'NO ACTION' delete_rule FROM duckdb_constraints() c, duckdb_constraints() f WHERE f.constraint_type = 'FOREIGN KEY' AND (c.constraint_type = 'UNIQUE' OR c.constraint_type = 'PRIMARY KEY') AND f.database_oid = c.database_oid AND f.schema_oid = c.schema_oid AND lower(f.referenced_table) = lower(c.table_name) AND [lower(x) for x in f.referenced_column_names] = [lower(x) for x in c.constraint_column_names]"}, - {"information_schema", "key_column_usage", "SELECT database_name constraint_catalog, schema_name constraint_schema, constraint_name, database_name table_catalog, schema_name table_schema, table_name, UNNEST(constraint_column_names) column_name, UNNEST(generate_series(1, len(constraint_column_names))) ordinal_position, CASE constraint_type WHEN 'FOREIGN KEY' THEN 1 ELSE NULL END position_in_unique_constraint FROM duckdb_constraints() WHERE constraint_type = 'FOREIGN KEY' OR constraint_type = 'PRIMARY KEY' OR constraint_type = 'UNIQUE';"}, + {"information_schema", "key_column_usage", "SELECT database_name constraint_catalog, schema_name constraint_schema, constraint_name, database_name table_catalog, schema_name table_schema, table_name, UNNEST(constraint_column_names) column_name, UNNEST(generate_series(1, len(constraint_column_names))) ordinal_position, CASE constraint_type WHEN 'FOREIGN KEY' THEN UNNEST (generate_series(1, len(constraint_column_names))) ELSE NULL END position_in_unique_constraint FROM duckdb_constraints() WHERE constraint_type = 'FOREIGN KEY' OR constraint_type = 'PRIMARY KEY' OR constraint_type = 'UNIQUE';"}, {"information_schema", "table_constraints", "SELECT database_name constraint_catalog, schema_name constraint_schema, constraint_name, database_name table_catalog, schema_name table_schema, table_name, CASE constraint_type WHEN 'NOT NULL' THEN 'CHECK' ELSE constraint_type END constraint_type, 'NO' is_deferrable, 'NO' initially_deferred, 'YES' enforced, 'YES' nulls_distinct FROM duckdb_constraints() WHERE constraint_type = 'PRIMARY KEY' OR constraint_type = 'FOREIGN KEY' OR constraint_type = 'UNIQUE' OR constraint_type = 'CHECK' OR constraint_type = 'NOT NULL';"}, {"information_schema", "constraint_column_usage", "SELECT database_name AS table_catalog, schema_name AS table_schema, table_name, column_name, database_name AS constraint_catalog, schema_name AS constraint_schema, constraint_name, constraint_type, constraint_text FROM (SELECT dc.*, UNNEST(dc.constraint_column_names) AS column_name FROM duckdb_constraints() AS dc WHERE constraint_type NOT IN ('NOT NULL') );"}, {"information_schema", "constraint_table_usage", "SELECT database_name AS table_catalog, schema_name AS table_schema, table_name, database_name AS constraint_catalog, schema_name AS constraint_schema, constraint_name, constraint_type FROM duckdb_constraints() WHERE constraint_type NOT IN ('NOT NULL');"}, diff --git a/src/duckdb/src/catalog/dependency_manager.cpp b/src/duckdb/src/catalog/dependency_manager.cpp index 840310f7e..92d58991f 100644 --- a/src/duckdb/src/catalog/dependency_manager.cpp +++ b/src/duckdb/src/catalog/dependency_manager.cpp @@ -372,6 +372,9 @@ static string EntryToString(CatalogEntryInfo &info) { case CatalogType::COLLATION_ENTRY: { return StringUtil::Format("collation \"%s\"", info.name); } + case CatalogType::COORDINATE_SYSTEM_ENTRY: { + return StringUtil::Format("coordinate system \"%s\"", info.name); + } case CatalogType::TYPE_ENTRY: { return StringUtil::Format("type \"%s\"", info.name); } diff --git a/src/duckdb/src/common/adbc/adbc.cpp b/src/duckdb/src/common/adbc/adbc.cpp index 8cf16141d..6be6d70c9 100644 --- a/src/duckdb/src/common/adbc/adbc.cpp +++ b/src/duckdb/src/common/adbc/adbc.cpp @@ -8,6 +8,7 @@ #include "duckdb/common/arrow/arrow_wrapper.hpp" #include "duckdb/common/arrow/nanoarrow/nanoarrow.hpp" +#include "duckdb/common/exception.hpp" #include "duckdb/main/connection.hpp" #include "duckdb/common/adbc/options.h" #include "duckdb/common/adbc/single_batch_array_stream.hpp" @@ -69,36 +70,36 @@ AdbcStatusCode duckdb_adbc_init(int version, void *driver, struct AdbcError *err // TODO: ADBC 1.1.0 adds support for these functions adbc_driver->ErrorGetDetailCount = nullptr; adbc_driver->ErrorGetDetail = nullptr; - adbc_driver->ErrorFromArrayStream = nullptr; - - adbc_driver->DatabaseGetOption = nullptr; - adbc_driver->DatabaseGetOptionBytes = nullptr; - adbc_driver->DatabaseGetOptionDouble = nullptr; - adbc_driver->DatabaseGetOptionInt = nullptr; - adbc_driver->DatabaseSetOptionBytes = nullptr; - adbc_driver->DatabaseSetOptionInt = nullptr; - adbc_driver->DatabaseSetOptionDouble = nullptr; - - adbc_driver->ConnectionCancel = nullptr; - adbc_driver->ConnectionGetOption = nullptr; - adbc_driver->ConnectionGetOptionBytes = nullptr; - adbc_driver->ConnectionGetOptionDouble = nullptr; - adbc_driver->ConnectionGetOptionInt = nullptr; + adbc_driver->ErrorFromArrayStream = duckdb_adbc::ErrorFromArrayStream; + + adbc_driver->DatabaseGetOption = duckdb_adbc::DatabaseGetOption; + adbc_driver->DatabaseGetOptionBytes = duckdb_adbc::DatabaseGetOptionBytes; + adbc_driver->DatabaseGetOptionDouble = duckdb_adbc::DatabaseGetOptionDouble; + adbc_driver->DatabaseGetOptionInt = duckdb_adbc::DatabaseGetOptionInt; + adbc_driver->DatabaseSetOptionBytes = duckdb_adbc::DatabaseSetOptionBytes; + adbc_driver->DatabaseSetOptionInt = duckdb_adbc::DatabaseSetOptionInt; + adbc_driver->DatabaseSetOptionDouble = duckdb_adbc::DatabaseSetOptionDouble; + + adbc_driver->ConnectionCancel = duckdb_adbc::ConnectionCancel; + adbc_driver->ConnectionGetOption = duckdb_adbc::ConnectionGetOption; + adbc_driver->ConnectionGetOptionBytes = duckdb_adbc::ConnectionGetOptionBytes; + adbc_driver->ConnectionGetOptionDouble = duckdb_adbc::ConnectionGetOptionDouble; + adbc_driver->ConnectionGetOptionInt = duckdb_adbc::ConnectionGetOptionInt; adbc_driver->ConnectionGetStatistics = nullptr; adbc_driver->ConnectionGetStatisticNames = nullptr; - adbc_driver->ConnectionSetOptionBytes = nullptr; - adbc_driver->ConnectionSetOptionInt = nullptr; - adbc_driver->ConnectionSetOptionDouble = nullptr; + adbc_driver->ConnectionSetOptionBytes = duckdb_adbc::ConnectionSetOptionBytes; + adbc_driver->ConnectionSetOptionInt = duckdb_adbc::ConnectionSetOptionInt; + adbc_driver->ConnectionSetOptionDouble = duckdb_adbc::ConnectionSetOptionDouble; - adbc_driver->StatementCancel = nullptr; + adbc_driver->StatementCancel = duckdb_adbc::StatementCancel; adbc_driver->StatementExecuteSchema = nullptr; - adbc_driver->StatementGetOption = nullptr; - adbc_driver->StatementGetOptionBytes = nullptr; - adbc_driver->StatementGetOptionDouble = nullptr; - adbc_driver->StatementGetOptionInt = nullptr; - adbc_driver->StatementSetOptionBytes = nullptr; - adbc_driver->StatementSetOptionDouble = nullptr; - adbc_driver->StatementSetOptionInt = nullptr; + adbc_driver->StatementGetOption = duckdb_adbc::StatementGetOption; + adbc_driver->StatementGetOptionBytes = duckdb_adbc::StatementGetOptionBytes; + adbc_driver->StatementGetOptionDouble = duckdb_adbc::StatementGetOptionDouble; + adbc_driver->StatementGetOptionInt = duckdb_adbc::StatementGetOptionInt; + adbc_driver->StatementSetOptionBytes = duckdb_adbc::StatementSetOptionBytes; + adbc_driver->StatementSetOptionDouble = duckdb_adbc::StatementSetOptionDouble; + adbc_driver->StatementSetOptionInt = duckdb_adbc::StatementSetOptionInt; } return ADBC_STATUS_OK; @@ -123,8 +124,18 @@ struct DuckDBAdbcStatementWrapper { struct DuckDBAdbcStreamWrapper { duckdb_result result; + char *last_error; + AdbcStatusCode status_code; + AdbcError adbc_error; }; +static bool IsInterruptError(const char *message) { + if (!message) { + return false; + } + return std::strcmp(message, duckdb::InterruptException::INTERRUPT_MESSAGE) == 0; +} + static AdbcStatusCode QueryInternal(struct AdbcConnection *connection, struct ArrowArrayStream *out, const char *query, struct AdbcError *error) { AdbcStatement statement; @@ -161,8 +172,28 @@ struct DuckDBAdbcDatabaseWrapper { //! Derived path from ADBC "uri" option (after minimal normalization) std::string uri_path; bool uri_set = false; + //! Stores config options for round-tripping via GetOption (DuckDB does not have an API to get config options) + std::unordered_map config_options; }; +// Helper for the ADBC GetOption buffer convention (two-pass pattern): +// Per the ADBC spec, callers first query the required buffer size, then fetch the value: +// 1. Call with value=nullptr or *length=0 → *length is set to the required size (no data written). +// 2. Call again with a sufficiently sized buffer → value is filled and *length is set. +static AdbcStatusCode GetOptionStringHelper(const char *value_str, char *value, size_t *length, + struct AdbcError *error) { + if (!length) { + SetError(error, "Missing length pointer"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + size_t required = std::strlen(value_str) + 1; // include null terminator + if (*length >= required && value) { + std::memcpy(value, value_str, required); + } + *length = required; + return ADBC_STATUS_OK; +} + void InitializeADBCError(AdbcError *error) { if (!error) { return; @@ -227,6 +258,10 @@ AdbcStatusCode DatabaseSetOption(struct AdbcDatabase *database, const char *key, wrapper->path = value; return ADBC_STATUS_OK; } + if (strcmp(key, ADBC_OPTION_USERNAME) == 0 || strcmp(key, ADBC_OPTION_PASSWORD) == 0) { + SetError(error, "DuckDB does not support authentication"); + return ADBC_STATUS_NOT_IMPLEMENTED; + } if (strcmp(key, "uri") == 0) { if (strncmp(value, "file:", 5) != 0) { wrapper->uri_path = value; @@ -259,7 +294,9 @@ AdbcStatusCode DatabaseSetOption(struct AdbcDatabase *database, const char *key, return ADBC_STATUS_OK; } auto res = duckdb_set_config(wrapper->config, key, value); - + if (res == DuckDBSuccess) { + wrapper->config_options[key] = value; + } return CheckResult(res, error, "Failed to set configuration option"); } @@ -295,6 +332,90 @@ AdbcStatusCode DatabaseRelease(struct AdbcDatabase *database, struct AdbcError * return ADBC_STATUS_OK; } +// Database Typed Option API (ADBC 1.1.0) +AdbcStatusCode DatabaseGetOption(struct AdbcDatabase *database, const char *key, char *value, size_t *length, + struct AdbcError *error) { + if (!database || !database->private_data) { + SetError(error, "Missing database object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (!key) { + SetError(error, "Missing key"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto wrapper = static_cast(database->private_data); + if (strcmp(key, "path") == 0) { + return GetOptionStringHelper(wrapper->path.c_str(), value, length, error); + } + if (strcmp(key, ADBC_OPTION_USERNAME) == 0 || strcmp(key, ADBC_OPTION_PASSWORD) == 0) { + SetError(error, "DuckDB does not support authentication"); + return ADBC_STATUS_NOT_IMPLEMENTED; + } + if (strcmp(key, "uri") == 0) { + if (wrapper->uri_set) { + return GetOptionStringHelper(wrapper->uri_path.c_str(), value, length, error); + } + SetError(error, "Option not found: uri"); + return ADBC_STATUS_NOT_FOUND; + } + auto it = wrapper->config_options.find(key); + if (it != wrapper->config_options.end()) { + return GetOptionStringHelper(it->second.c_str(), value, length, error); + } + auto error_message = std::string("Option not found: ") + key; + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode DatabaseGetOptionBytes(struct AdbcDatabase *database, const char *key, uint8_t *value, size_t *length, + struct AdbcError *error) { + if (!database || !database->private_data) { + SetError(error, "Missing database object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto error_message = std::string("Option not found: ") + (key ? key : "(null)"); + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode DatabaseGetOptionDouble(struct AdbcDatabase *database, const char *key, double *value, + struct AdbcError *error) { + if (!database || !database->private_data) { + SetError(error, "Missing database object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto error_message = std::string("Option not found: ") + (key ? key : "(null)"); + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode DatabaseGetOptionInt(struct AdbcDatabase *database, const char *key, int64_t *value, + struct AdbcError *error) { + if (!database || !database->private_data) { + SetError(error, "Missing database object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto error_message = std::string("Option not found: ") + (key ? key : "(null)"); + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode DatabaseSetOptionBytes(struct AdbcDatabase *database, const char *key, const uint8_t *value, + size_t length, struct AdbcError *error) { + SetError(error, "SetOptionBytes is not supported for database"); + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode DatabaseSetOptionInt(struct AdbcDatabase *database, const char *key, int64_t value, + struct AdbcError *error) { + return DatabaseSetOption(database, key, std::to_string(value).c_str(), error); +} + +AdbcStatusCode DatabaseSetOptionDouble(struct AdbcDatabase *database, const char *key, double value, + struct AdbcError *error) { + return DatabaseSetOption(database, key, std::to_string(value).c_str(), error); +} + AdbcStatusCode ConnectionGetTableSchema(struct AdbcConnection *connection, const char *catalog, const char *db_schema, const char *table_name, struct ArrowSchema *schema, struct AdbcError *error) { if (!connection) { @@ -342,7 +463,7 @@ AdbcStatusCode ConnectionNew(struct AdbcConnection *connection, struct AdbcError return ADBC_STATUS_OK; } -AdbcStatusCode ExecuteQuery(duckdb::Connection *conn, const char *query, struct AdbcError *error) { +static AdbcStatusCode ExecuteQuery(duckdb::Connection *conn, const char *query, struct AdbcError *error) { auto res = conn->Query(query); if (res->HasError()) { auto error_message = "Failed to execute query \"" + std::string(query) + "\": " + res->GetError(); @@ -352,8 +473,8 @@ AdbcStatusCode ExecuteQuery(duckdb::Connection *conn, const char *query, struct return ADBC_STATUS_OK; } -AdbcStatusCode InternalSetOption(duckdb::Connection &conn, std::unordered_map &options, - struct AdbcError *error) { +static AdbcStatusCode InternalSetOption(duckdb::Connection &conn, std::unordered_map &options, + struct AdbcError *error) { // If we got here, the options have already been validated and are acceptable for (auto &option : options) { if (strcmp(option.first.c_str(), ADBC_CONNECTION_OPTION_AUTOCOMMIT) == 0) { @@ -379,12 +500,29 @@ AdbcStatusCode InternalSetOption(duckdb::Connection &conn, std::unordered_mapconnection) { + SetError(error, "Connection is not initialized"); + return ADBC_STATUS_INVALID_STATE; + } + auto conn = reinterpret_cast(conn_wrapper->connection); + std::string query = sql_prefix + duckdb::KeywordHelper::WriteOptionallyQuoted(value); + return ExecuteQuery(conn, query.c_str(), error); +} + AdbcStatusCode ConnectionSetOption(struct AdbcConnection *connection, const char *key, const char *value, struct AdbcError *error) { if (!connection) { SetError(error, "Connection is not set"); return ADBC_STATUS_INVALID_ARGUMENT; } + if (!value) { + SetError(error, "Option value must not be NULL"); + return ADBC_STATUS_INVALID_ARGUMENT; + } std::string key_string = std::string(key); std::string key_value = std::string(value); auto conn_wrapper = static_cast(connection->private_data); @@ -398,19 +536,188 @@ AdbcStatusCode ConnectionSetOption(struct AdbcConnection *connection, const char SetError(error, error_message); return ADBC_STATUS_INVALID_ARGUMENT; } - } else { - // This is an unknown option to the DuckDB driver - auto error_message = - "Unknown connection option " + std::string(key) + "=" + (value ? std::string(value) : "(NULL)"); - SetError(error, error_message); - return ADBC_STATUS_NOT_IMPLEMENTED; + if (!conn_wrapper->connection) { + // If the connection has not yet been initialized, we just return here. + return ADBC_STATUS_OK; + } + auto conn = reinterpret_cast(conn_wrapper->connection); + return InternalSetOption(*conn, conn_wrapper->options, error); } - if (!conn_wrapper->connection) { - // If the connection has not yet been initialized, we just return here. + if (strcmp(key, ADBC_CONNECTION_OPTION_CURRENT_CATALOG) == 0) { + return ConnectionSetOptionCurrentValue(conn_wrapper, "USE ", value, error); + } + if (strcmp(key, ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA) == 0) { + return ConnectionSetOptionCurrentValue(conn_wrapper, "SET schema = ", value, error); + } + // This is an unknown option to the DuckDB driver + auto error_message = + "Unknown connection option " + std::string(key) + "=" + (value ? std::string(value) : "(NULL)"); + SetError(error, error_message); + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +// Connection Typed Option API (ADBC 1.1.0) +AdbcStatusCode ConnectionGetOption(struct AdbcConnection *connection, const char *key, char *value, size_t *length, + struct AdbcError *error) { + if (!connection || !connection->private_data) { + SetError(error, "Connection is not set"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (!key) { + SetError(error, "Missing key"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto conn_wrapper = static_cast(connection->private_data); + if (strcmp(key, ADBC_CONNECTION_OPTION_AUTOCOMMIT) == 0) { + if (conn_wrapper->connection) { + auto conn = reinterpret_cast(conn_wrapper->connection); + const char *val = conn->IsAutoCommit() ? ADBC_OPTION_VALUE_ENABLED : ADBC_OPTION_VALUE_DISABLED; + return GetOptionStringHelper(val, value, length, error); + } + // Not yet initialized; check pending options, default is "true" + auto it = conn_wrapper->options.find(ADBC_CONNECTION_OPTION_AUTOCOMMIT); + const char *val = (it != conn_wrapper->options.end()) ? it->second.c_str() : ADBC_OPTION_VALUE_ENABLED; + return GetOptionStringHelper(val, value, length, error); + } + if (strcmp(key, ADBC_CONNECTION_OPTION_CURRENT_CATALOG) == 0) { + if (!conn_wrapper->connection) { + SetError(error, "Connection is not initialized"); + return ADBC_STATUS_INVALID_STATE; + } + ArrowArrayStream stream; + auto status = QueryInternal(connection, &stream, "SELECT current_database()", error); + if (status != ADBC_STATUS_OK) { + return status; + } + ArrowArray batch; + batch.release = nullptr; + stream.get_next(&stream, &batch); + if (!batch.release || batch.length < 1 || batch.n_children < 1) { + if (batch.release) { + batch.release(&batch); + } + stream.release(&stream); + SetError(error, "Failed to get current catalog"); + return ADBC_STATUS_INTERNAL; + } + // Access the first column (VARCHAR): buffers are [validity, offsets, data] + auto *col = batch.children[0]; + auto offsets = static_cast(col->buffers[1]); + auto data = static_cast(col->buffers[2]); + std::string result(data + offsets[0], static_cast(offsets[1] - offsets[0])); + batch.release(&batch); + stream.release(&stream); + return GetOptionStringHelper(result.c_str(), value, length, error); + } + if (strcmp(key, ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA) == 0) { + if (!conn_wrapper->connection) { + SetError(error, "Connection is not initialized"); + return ADBC_STATUS_INVALID_STATE; + } + ArrowArrayStream stream; + auto status = QueryInternal(connection, &stream, "SELECT current_schema()", error); + if (status != ADBC_STATUS_OK) { + return status; + } + ArrowArray batch; + batch.release = nullptr; + stream.get_next(&stream, &batch); + if (!batch.release || batch.length < 1 || batch.n_children < 1) { + if (batch.release) { + batch.release(&batch); + } + stream.release(&stream); + SetError(error, "Failed to get current schema"); + return ADBC_STATUS_INTERNAL; + } + auto *col = batch.children[0]; + auto offsets = static_cast(col->buffers[1]); + auto data = static_cast(col->buffers[2]); + std::string result(data + offsets[0], static_cast(offsets[1] - offsets[0])); + batch.release(&batch); + stream.release(&stream); + return GetOptionStringHelper(result.c_str(), value, length, error); + } + auto error_message = std::string("Option not found: ") + key; + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode ConnectionGetOptionBytes(struct AdbcConnection *connection, const char *key, uint8_t *value, + size_t *length, struct AdbcError *error) { + if (!connection || !connection->private_data) { + SetError(error, "Connection is not set"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto error_message = std::string("Option not found: ") + (key ? key : "(null)"); + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode ConnectionGetOptionDouble(struct AdbcConnection *connection, const char *key, double *value, + struct AdbcError *error) { + if (!connection || !connection->private_data) { + SetError(error, "Connection is not set"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto error_message = std::string("Option not found: ") + (key ? key : "(null)"); + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode ConnectionGetOptionInt(struct AdbcConnection *connection, const char *key, int64_t *value, + struct AdbcError *error) { + if (!connection || !connection->private_data) { + SetError(error, "Connection is not set"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (!key) { + SetError(error, "Missing key"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (strcmp(key, ADBC_CONNECTION_OPTION_AUTOCOMMIT) == 0) { + auto conn_wrapper = static_cast(connection->private_data); + if (conn_wrapper->connection) { + auto conn = reinterpret_cast(conn_wrapper->connection); + *value = conn->IsAutoCommit() ? 1 : 0; + return ADBC_STATUS_OK; + } + auto it = conn_wrapper->options.find(ADBC_CONNECTION_OPTION_AUTOCOMMIT); + if (it != conn_wrapper->options.end()) { + *value = (it->second == ADBC_OPTION_VALUE_ENABLED) ? 1 : 0; + } else { + *value = 1; // default is autocommit enabled + } return ADBC_STATUS_OK; } - auto conn = reinterpret_cast(conn_wrapper->connection); - return InternalSetOption(*conn, conn_wrapper->options, error); + auto error_message = std::string("Option not found: ") + key; + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode ConnectionSetOptionBytes(struct AdbcConnection *connection, const char *key, const uint8_t *value, + size_t length, struct AdbcError *error) { + SetError(error, "SetOptionBytes is not supported for connection"); + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode ConnectionSetOptionInt(struct AdbcConnection *connection, const char *key, int64_t value, + struct AdbcError *error) { + if (!key) { + SetError(error, "Missing key"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (strcmp(key, ADBC_CONNECTION_OPTION_AUTOCOMMIT) == 0) { + const char *str_value = value ? ADBC_OPTION_VALUE_ENABLED : ADBC_OPTION_VALUE_DISABLED; + return ConnectionSetOption(connection, key, str_value, error); + } + return ConnectionSetOption(connection, key, std::to_string(value).c_str(), error); +} + +AdbcStatusCode ConnectionSetOptionDouble(struct AdbcConnection *connection, const char *key, double value, + struct AdbcError *error) { + SetError(error, "SetOptionDouble is not supported for connection"); + return ADBC_STATUS_NOT_IMPLEMENTED; } AdbcStatusCode ConnectionReadPartition(struct AdbcConnection *connection, const uint8_t *serialized_partition, @@ -465,6 +772,24 @@ AdbcStatusCode ConnectionRollback(struct AdbcConnection *connection, struct Adbc return ExecuteQuery(conn, "START TRANSACTION", error); } +AdbcStatusCode ConnectionCancel(struct AdbcConnection *connection, struct AdbcError *error) { + if (!connection) { + SetError(error, "Missing connection object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (!connection->private_data) { + SetError(error, "Connection is invalid"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto conn_wrapper = static_cast(connection->private_data); + if (!conn_wrapper->connection) { + SetError(error, "Connection is not initialized"); + return ADBC_STATUS_INVALID_STATE; + } + duckdb_interrupt(conn_wrapper->connection); + return ADBC_STATUS_OK; +} + enum class AdbcInfoCode : uint32_t { VENDOR_NAME, VENDOR_VERSION, @@ -678,6 +1003,20 @@ static int get_next(struct ArrowArrayStream *stream, struct ArrowArray *out) { auto result_wrapper = static_cast(stream->private_data); auto duckdb_chunk = duckdb_fetch_chunk(result_wrapper->result); if (!duckdb_chunk) { + // End of stream or error; distinguish by checking the result error message. + auto err = duckdb_result_error(&result_wrapper->result); + if (err && err[0] != '\0') { + if (result_wrapper->last_error) { + free(result_wrapper->last_error); + } + result_wrapper->last_error = strdup(err); + result_wrapper->status_code = IsInterruptError(err) ? ADBC_STATUS_CANCELLED : ADBC_STATUS_INTERNAL; + // Populate adbc_error for AdbcErrorFromArrayStream + result_wrapper->adbc_error.message = result_wrapper->last_error; + result_wrapper->adbc_error.vendor_code = 0; + result_wrapper->adbc_error.release = nullptr; + return DuckDBError; + } return DuckDBSuccess; } auto arrow_options = duckdb_result_get_arrow_options(&result_wrapper->result); @@ -700,6 +1039,12 @@ void release(struct ArrowArrayStream *stream) { auto result_wrapper = reinterpret_cast(stream->private_data); if (result_wrapper) { duckdb_destroy_result(&result_wrapper->result); + if (result_wrapper->last_error) { + free(result_wrapper->last_error); + result_wrapper->last_error = nullptr; + } + // Release any error that was set on the stream wrapper + InitializeADBCError(&result_wrapper->adbc_error); } free(stream->private_data); stream->private_data = nullptr; @@ -707,7 +1052,29 @@ void release(struct ArrowArrayStream *stream) { } const char *get_last_error(struct ArrowArrayStream *stream) { - return nullptr; + if (!stream || !stream->private_data) { + return nullptr; + } + auto result_wrapper = reinterpret_cast(stream->private_data); + return result_wrapper ? result_wrapper->last_error : nullptr; +} + +const AdbcError *ErrorFromArrayStream(struct ArrowArrayStream *stream, AdbcStatusCode *status) { + if (!stream || !stream->private_data) { + return nullptr; + } + // Verify the stream comes from this driver by checking the release function + if (stream->release != release) { + return nullptr; + } + auto result_wrapper = reinterpret_cast(stream->private_data); + if (!result_wrapper->last_error) { + return nullptr; + } + if (status) { + *status = result_wrapper->status_code; + } + return &result_wrapper->adbc_error; } // this is an evil hack, normally we would need a stream factory here, but its probably much easier if the adbc clients @@ -835,9 +1202,13 @@ AdbcStatusCode Ingest(duckdb_connection connection, const char *catalog, const c duckdb_result result; if (duckdb_query(connection, sql.c_str(), &result) == DuckDBError) { const char *error_msg = duckdb_result_error(&result); - // Check if error is about table already existing before destroying result bool already_exists = error_msg && std::string(error_msg).find("already exists") != std::string::npos; + bool interrupted = IsInterruptError(error_msg); + SetError(error, error_msg); duckdb_destroy_result(&result); + if (interrupted) { + return ADBC_STATUS_CANCELLED; + } if (already_exists) { return ADBC_STATUS_ALREADY_EXISTS; } @@ -856,9 +1227,10 @@ AdbcStatusCode Ingest(duckdb_connection connection, const char *catalog, const c BuildCreateTableSQL(effective_catalog, effective_schema, table_name, types, names, false, temporary, true); duckdb_result result; if (duckdb_query(connection, create_sql.c_str(), &result) == DuckDBError) { - SetError(error, duckdb_result_error(&result)); + auto err = duckdb_result_error(&result); + SetError(error, err); duckdb_destroy_result(&result); - return ADBC_STATUS_INTERNAL; + return IsInterruptError(err) ? ADBC_STATUS_CANCELLED : ADBC_STATUS_INTERNAL; } duckdb_destroy_result(&result); break; @@ -868,9 +1240,10 @@ AdbcStatusCode Ingest(duckdb_connection connection, const char *catalog, const c auto sql = BuildCreateTableSQL(effective_catalog, effective_schema, table_name, types, names, true, temporary); duckdb_result result; if (duckdb_query(connection, sql.c_str(), &result) == DuckDBError) { - SetError(error, duckdb_result_error(&result)); + auto err = duckdb_result_error(&result); + SetError(error, err); duckdb_destroy_result(&result); - return ADBC_STATUS_INTERNAL; + return IsInterruptError(err) ? ADBC_STATUS_CANCELLED : ADBC_STATUS_INTERNAL; } duckdb_destroy_result(&result); break; @@ -901,9 +1274,11 @@ AdbcStatusCode Ingest(duckdb_connection connection, const char *catalog, const c } if (duckdb_append_data_chunk(appender.Get(), out_chunk.chunk) != DuckDBSuccess) { auto error_data = duckdb_appender_error_data(appender.Get()); - SetError(error, duckdb_error_data_message(error_data)); + auto err = duckdb_error_data_message(error_data); + SetError(error, err); + bool interrupted = IsInterruptError(err); duckdb_destroy_error_data(&error_data); - return ADBC_STATUS_INTERNAL; + return interrupted ? ADBC_STATUS_CANCELLED : ADBC_STATUS_INTERNAL; } arrow_array_wrapper = duckdb::ArrowArrayWrapper(); input->get_next(input, &arrow_array_wrapper.arrow_array); @@ -982,6 +1357,26 @@ AdbcStatusCode StatementRelease(struct AdbcStatement *statement, struct AdbcErro return ADBC_STATUS_OK; } +AdbcStatusCode StatementCancel(struct AdbcStatement *statement, struct AdbcError *error) { + if (!statement) { + SetError(error, "Missing statement object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (!statement->private_data) { + SetError(error, "Invalid statement object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto wrapper = static_cast(statement->private_data); + if (!wrapper->connection) { + // Statement has been released or is not properly initialized. + // Return INVALID_ARGUMENT since the statement object itself is invalid. + SetError(error, "Invalid statement object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + duckdb_interrupt(wrapper->connection); + return ADBC_STATUS_OK; +} + AdbcStatusCode StatementGetParameterSchema(struct AdbcStatement *statement, struct ArrowSchema *schema, struct AdbcError *error) { if (!statement) { @@ -1065,6 +1460,10 @@ AdbcStatusCode StatementExecuteQuery(struct AdbcStatement *statement, struct Arr return ADBC_STATUS_INVALID_ARGUMENT; } auto wrapper = static_cast(statement->private_data); + if (!wrapper->connection) { + SetError(error, "Invalid connection"); + return ADBC_STATUS_INVALID_STATE; + } // TODO: Set affected rows, careful with early return if (rows_affected) { @@ -1098,6 +1497,9 @@ AdbcStatusCode StatementExecuteQuery(struct AdbcStatement *statement, struct Arr SetError(error, "Allocation error"); return ADBC_STATUS_INVALID_ARGUMENT; } + stream_wrapper->last_error = nullptr; + stream_wrapper->status_code = ADBC_STATUS_OK; + std::memset(&stream_wrapper->adbc_error, 0, sizeof(stream_wrapper->adbc_error)); std::memset(&stream_wrapper->result, 0, sizeof(stream_wrapper->result)); // Only process the stream if there are parameters to bind auto prepared_statement_params = reinterpret_cast(wrapper->statement) @@ -1169,24 +1571,26 @@ AdbcStatusCode StatementExecuteQuery(struct AdbcStatement *statement, struct Arr } // Destroy any previous result before overwriting to avoid leaks duckdb_destroy_result(&stream_wrapper->result); - auto res = duckdb_execute_prepared(wrapper->statement, &stream_wrapper->result); + auto res = duckdb_execute_prepared_streaming(wrapper->statement, &stream_wrapper->result); if (res != DuckDBSuccess) { - SetError(error, duckdb_result_error(&stream_wrapper->result)); + auto err = duckdb_result_error(&stream_wrapper->result); + SetError(error, err); duckdb_destroy_result(&stream_wrapper->result); free(stream_wrapper); - return ADBC_STATUS_INVALID_ARGUMENT; + return IsInterruptError(err) ? ADBC_STATUS_CANCELLED : ADBC_STATUS_INVALID_ARGUMENT; } // Recreate wrappers for next iteration arrow_array_wrapper = duckdb::ArrowArrayWrapper(); stream.get_next(&stream, &arrow_array_wrapper.arrow_array); } } else { - auto res = duckdb_execute_prepared(wrapper->statement, &stream_wrapper->result); + auto res = duckdb_execute_prepared_streaming(wrapper->statement, &stream_wrapper->result); if (res != DuckDBSuccess) { - SetError(error, duckdb_result_error(&stream_wrapper->result)); + auto err = duckdb_result_error(&stream_wrapper->result); + SetError(error, err); duckdb_destroy_result(&stream_wrapper->result); free(stream_wrapper); - return ADBC_STATUS_INVALID_ARGUMENT; + return IsInterruptError(err) ? ADBC_STATUS_CANCELLED : ADBC_STATUS_INVALID_ARGUMENT; } } @@ -1458,6 +1862,133 @@ AdbcStatusCode StatementSetOption(struct AdbcStatement *statement, const char *k return ADBC_STATUS_INVALID_ARGUMENT; } +// Statement Typed Option API (ADBC 1.1.0) +static const char *IngestionModeToString(IngestionMode mode) { + switch (mode) { + case IngestionMode::CREATE: + return ADBC_INGEST_OPTION_MODE_CREATE; + case IngestionMode::APPEND: + return ADBC_INGEST_OPTION_MODE_APPEND; + case IngestionMode::REPLACE: + return ADBC_INGEST_OPTION_MODE_REPLACE; + case IngestionMode::CREATE_APPEND: + return ADBC_INGEST_OPTION_MODE_CREATE_APPEND; + default: + return ADBC_INGEST_OPTION_MODE_CREATE; + } +} + +AdbcStatusCode StatementGetOption(struct AdbcStatement *statement, const char *key, char *value, size_t *length, + struct AdbcError *error) { + if (!statement || !statement->private_data) { + SetError(error, "Invalid statement object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (!key) { + SetError(error, "Missing key"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto wrapper = static_cast(statement->private_data); + if (strcmp(key, ADBC_INGEST_OPTION_TARGET_TABLE) == 0) { + if (wrapper->ingestion_table_name) { + return GetOptionStringHelper(wrapper->ingestion_table_name, value, length, error); + } + SetError(error, "Option not set: " ADBC_INGEST_OPTION_TARGET_TABLE); + return ADBC_STATUS_NOT_FOUND; + } + if (strcmp(key, ADBC_INGEST_OPTION_TEMPORARY) == 0) { + const char *val = wrapper->temporary_table ? ADBC_OPTION_VALUE_ENABLED : ADBC_OPTION_VALUE_DISABLED; + return GetOptionStringHelper(val, value, length, error); + } + if (strcmp(key, ADBC_INGEST_OPTION_TARGET_DB_SCHEMA) == 0) { + if (wrapper->db_schema) { + return GetOptionStringHelper(wrapper->db_schema, value, length, error); + } + SetError(error, "Option not set: " ADBC_INGEST_OPTION_TARGET_DB_SCHEMA); + return ADBC_STATUS_NOT_FOUND; + } + if (strcmp(key, ADBC_INGEST_OPTION_TARGET_CATALOG) == 0) { + if (wrapper->target_catalog) { + return GetOptionStringHelper(wrapper->target_catalog, value, length, error); + } + SetError(error, "Option not set: " ADBC_INGEST_OPTION_TARGET_CATALOG); + return ADBC_STATUS_NOT_FOUND; + } + if (strcmp(key, ADBC_INGEST_OPTION_MODE) == 0) { + return GetOptionStringHelper(IngestionModeToString(wrapper->ingestion_mode), value, length, error); + } + auto error_message = std::string("Option not found: ") + key; + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode StatementGetOptionBytes(struct AdbcStatement *statement, const char *key, uint8_t *value, size_t *length, + struct AdbcError *error) { + if (!statement || !statement->private_data) { + SetError(error, "Invalid statement object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto error_message = std::string("Option not found: ") + (key ? key : "(null)"); + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode StatementGetOptionDouble(struct AdbcStatement *statement, const char *key, double *value, + struct AdbcError *error) { + if (!statement || !statement->private_data) { + SetError(error, "Invalid statement object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto error_message = std::string("Option not found: ") + (key ? key : "(null)"); + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode StatementGetOptionInt(struct AdbcStatement *statement, const char *key, int64_t *value, + struct AdbcError *error) { + if (!statement || !statement->private_data) { + SetError(error, "Invalid statement object"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (!key) { + SetError(error, "Missing key"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + auto wrapper = static_cast(statement->private_data); + if (strcmp(key, ADBC_INGEST_OPTION_TEMPORARY) == 0) { + *value = wrapper->temporary_table ? 1 : 0; + return ADBC_STATUS_OK; + } + auto error_message = std::string("Option not found: ") + key; + SetError(error, error_message); + return ADBC_STATUS_NOT_FOUND; +} + +AdbcStatusCode StatementSetOptionBytes(struct AdbcStatement *statement, const char *key, const uint8_t *value, + size_t length, struct AdbcError *error) { + SetError(error, "SetOptionBytes is not supported for statement"); + return ADBC_STATUS_NOT_IMPLEMENTED; +} + +AdbcStatusCode StatementSetOptionInt(struct AdbcStatement *statement, const char *key, int64_t value, + struct AdbcError *error) { + if (!key) { + SetError(error, "Missing key"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + if (strcmp(key, ADBC_INGEST_OPTION_TEMPORARY) == 0) { + const char *str_value = value ? ADBC_OPTION_VALUE_ENABLED : ADBC_OPTION_VALUE_DISABLED; + return StatementSetOption(statement, key, str_value, error); + } + return StatementSetOption(statement, key, std::to_string(value).c_str(), error); +} + +AdbcStatusCode StatementSetOptionDouble(struct AdbcStatement *statement, const char *key, double value, + struct AdbcError *error) { + SetError(error, "SetOptionDouble is not supported for statement"); + return ADBC_STATUS_NOT_IMPLEMENTED; +} + std::string createFilter(const char *input) { if (input) { auto quoted = duckdb::KeywordHelper::WriteQuoted(input, '\''); @@ -1808,7 +2339,13 @@ void SetError(struct AdbcError *error, const std::string &message) { buffer.reserve(buffer.size() + message.size() + 1); buffer += '\n'; buffer += message; - error->release(error); + // Release the old message safely - release may be nullptr if error was already released + if (error->release) { + error->release(error); + } else { + delete[] error->message; + error->message = nullptr; + } error->message = new char[buffer.size() + 1]; buffer.copy(error->message, buffer.size()); diff --git a/src/duckdb/src/common/allocator.cpp b/src/duckdb/src/common/allocator.cpp index c82302b48..4ee952fc4 100644 --- a/src/duckdb/src/common/allocator.cpp +++ b/src/duckdb/src/common/allocator.cpp @@ -136,8 +136,7 @@ data_ptr_t Allocator::AllocateData(idx_t size) { } auto result = allocate_function(private_data.get(), size); #ifdef DEBUG - D_ASSERT(private_data); - if (private_data->free_type != AllocatorFreeType::DOES_NOT_REQUIRE_FREE) { + if (ShouldUseDebugInfo()) { private_data->debug_info->AllocateData(result, size); } #endif @@ -153,8 +152,7 @@ void Allocator::FreeData(data_ptr_t pointer, idx_t size) { } D_ASSERT(size > 0); #ifdef DEBUG - D_ASSERT(private_data); - if (private_data->free_type != AllocatorFreeType::DOES_NOT_REQUIRE_FREE) { + if (ShouldUseDebugInfo()) { private_data->debug_info->FreeData(pointer, size); } #endif @@ -173,8 +171,7 @@ data_ptr_t Allocator::ReallocateData(data_ptr_t pointer, idx_t old_size, idx_t s } auto new_pointer = reallocate_function(private_data.get(), pointer, old_size, size); #ifdef DEBUG - D_ASSERT(private_data); - if (private_data->free_type != AllocatorFreeType::DOES_NOT_REQUIRE_FREE) { + if (ShouldUseDebugInfo()) { private_data->debug_info->ReallocateData(pointer, new_pointer, old_size, size); } #endif diff --git a/src/duckdb/src/common/arrow/arrow_converter.cpp b/src/duckdb/src/common/arrow/arrow_converter.cpp index 8994151e2..85632a38c 100644 --- a/src/duckdb/src/common/arrow/arrow_converter.cpp +++ b/src/duckdb/src/common/arrow/arrow_converter.cpp @@ -160,6 +160,7 @@ void SetArrowFormat(DuckDBArrowSchemaHolder &root_holder, ArrowSchema &child, co case LogicalTypeId::FLOAT: child.format = "f"; break; + case LogicalTypeId::UHUGEINT: case LogicalTypeId::HUGEINT: { if (options.arrow_lossless_conversion) { SetArrowExtension(root_holder, child, type, context); diff --git a/src/duckdb/src/common/arrow/arrow_type_extension.cpp b/src/duckdb/src/common/arrow/arrow_type_extension.cpp index d3dff923c..97ece72f7 100644 --- a/src/duckdb/src/common/arrow/arrow_type_extension.cpp +++ b/src/duckdb/src/common/arrow/arrow_type_extension.cpp @@ -6,6 +6,7 @@ #include "duckdb/common/arrow/arrow_converter.hpp" #include "duckdb/common/arrow/schema_metadata.hpp" #include "duckdb/common/types/vector.hpp" +#include "duckdb/common/types/geometry_crs.hpp" #include "yyjson.hpp" @@ -128,10 +129,10 @@ ArrowExtensionMetadata ArrowTypeExtension::GetInfo() const { return extension_metadata; } -unique_ptr ArrowTypeExtension::GetType(const ArrowSchema &schema, +unique_ptr ArrowTypeExtension::GetType(ClientContext &context, const ArrowSchema &schema, const ArrowSchemaMetadata &schema_metadata) const { if (get_type) { - return get_type(schema, schema_metadata); + return get_type(context, schema, schema_metadata); } // FIXME: THis is not good auto duckdb_type = type_extension->GetDuckDBType(); @@ -259,7 +260,8 @@ bool DBConfig::HasArrowExtension(ArrowExtensionMetadata info) const { } struct ArrowJson { - static unique_ptr GetType(const ArrowSchema &schema, const ArrowSchemaMetadata &schema_metadata) { + static unique_ptr GetType(ClientContext &context, const ArrowSchema &schema, + const ArrowSchemaMetadata &schema_metadata) { const auto format = string(schema.format); if (format == "u") { return make_uniq(LogicalType::JSON(), make_uniq(ArrowVariableSizeType::NORMAL)); @@ -292,7 +294,8 @@ struct ArrowJson { }; struct ArrowBit { - static unique_ptr GetType(const ArrowSchema &schema, const ArrowSchemaMetadata &schema_metadata) { + static unique_ptr GetType(ClientContext &context, const ArrowSchema &schema, + const ArrowSchemaMetadata &schema_metadata) { const auto format = string(schema.format); if (format == "z") { return make_uniq(LogicalType::BIT, make_uniq(ArrowVariableSizeType::NORMAL)); @@ -319,7 +322,8 @@ struct ArrowBit { }; struct ArrowBignum { - static unique_ptr GetType(const ArrowSchema &schema, const ArrowSchemaMetadata &schema_metadata) { + static unique_ptr GetType(ClientContext &context, const ArrowSchema &schema, + const ArrowSchemaMetadata &schema_metadata) { const auto format = string(schema.format); if (format == "z") { return make_uniq(LogicalType::BIGNUM, make_uniq(ArrowVariableSizeType::NORMAL)); @@ -368,10 +372,14 @@ struct ArrowBool8 { }; struct ArrowGeometry { - static unique_ptr GetType(const ArrowSchema &schema, const ArrowSchemaMetadata &schema_metadata) { + static unique_ptr GetType(ClientContext &context, const ArrowSchema &schema, + const ArrowSchemaMetadata &schema_metadata) { // Validate extension metadata. This metadata also contains a CRS, which we drop // because the GEOMETRY type does not implement a CRS at the type level (yet). const auto extension_metadata = schema_metadata.GetOption(ArrowSchemaMetadata::ARROW_METADATA_KEY); + + unique_ptr duckdb_crs; + if (!extension_metadata.empty()) { unique_ptr doc( duckdb_yyjson::yyjson_read(extension_metadata.data(), extension_metadata.size(), @@ -390,29 +398,134 @@ struct ArrowGeometry { if (edges && yyjson_is_str(edges) && std::strcmp(yyjson_get_str(edges), "planar") != 0) { throw NotImplementedException("Can't import non-planar edges"); } + + // Pick out the CRS if present + duckdb_yyjson::yyjson_val *crs = yyjson_obj_get(val, "crs"); + + if (crs) { + if (duckdb_yyjson::yyjson_is_str(crs)) { + const char *crs_str = duckdb_yyjson::yyjson_get_str(crs); + duckdb_crs = CoordinateReferenceSystem::TryIdentify(context, crs_str); + } else if (duckdb_yyjson::yyjson_is_obj(crs)) { + // Stringify the object + duckdb_yyjson::yyjson_write_flag write_flags = duckdb_yyjson::YYJSON_WRITE_NOFLAG; + size_t len = 0; + const auto crs_str = duckdb_yyjson::yyjson_val_write(crs, write_flags, &len); + if (crs_str) { + const auto str = string(crs_str, len); + free(crs_str); + duckdb_crs = CoordinateReferenceSystem::TryIdentify(context, str); + } else { + throw SerializationException("Could not serialize CRS object from GeoArrow metadata"); + } + } + } } + // Create the geometry type, with or without CRS + auto geo_type = duckdb_crs ? LogicalType::GEOMETRY(*duckdb_crs) : LogicalType::GEOMETRY(); + const auto format = string(schema.format); if (format == "z") { - return make_uniq(LogicalType::GEOMETRY(), - make_uniq(ArrowVariableSizeType::NORMAL)); + return make_uniq(std::move(geo_type), make_uniq(ArrowVariableSizeType::NORMAL)); } if (format == "Z") { - return make_uniq(LogicalType::GEOMETRY(), + return make_uniq(std::move(geo_type), make_uniq(ArrowVariableSizeType::SUPER_SIZE)); } if (format == "vz") { - return make_uniq(LogicalType::GEOMETRY(), - make_uniq(ArrowVariableSizeType::VIEW)); + return make_uniq(std::move(geo_type), make_uniq(ArrowVariableSizeType::VIEW)); } throw InvalidInputException("Arrow extension type \"%s\" not supported for geoarrow.wkb", format.c_str()); } + static void WriteCRS(duckdb_yyjson::yyjson_mut_doc *doc, const CoordinateReferenceSystem &crs, + ClientContext &context) { + // Try to convert to preferred formats, in order + auto converted = CoordinateReferenceSystem::TryConvert(context, crs, CoordinateReferenceSystemType::PROJJSON); + if (!converted) { + converted = CoordinateReferenceSystem::TryConvert(context, crs, CoordinateReferenceSystemType::WKT2_2019); + } + if (!converted) { + converted = CoordinateReferenceSystem::TryConvert(context, crs, CoordinateReferenceSystemType::AUTH_CODE); + } + if (!converted) { + converted = CoordinateReferenceSystem::TryConvert(context, crs, CoordinateReferenceSystemType::SRID); + } + if (!converted) { + converted = nullptr; + } + + const auto &crs_def = converted ? converted->GetDefinition() : crs.GetDefinition(); + const auto &crs_type = converted ? converted->GetType() : crs.GetType(); + + const auto root = duckdb_yyjson::yyjson_mut_doc_get_root(doc); + + switch (crs_type) { + case CoordinateReferenceSystemType::PROJJSON: { + const auto projjson_doc = + duckdb_yyjson::yyjson_read(crs_def.c_str(), crs_def.size(), duckdb_yyjson::YYJSON_READ_NOFLAG); + if (projjson_doc) { + const auto projjson_val = duckdb_yyjson::yyjson_doc_get_root(projjson_doc); + const auto projjson_obj = duckdb_yyjson::yyjson_val_mut_copy(doc, projjson_val); + + duckdb_yyjson::yyjson_mut_obj_add_str(doc, root, "crs_type", "projjson"); + duckdb_yyjson::yyjson_mut_obj_add_val(doc, root, "crs", projjson_obj); + + duckdb_yyjson::yyjson_doc_free(projjson_doc); + } else { + duckdb_yyjson::yyjson_mut_doc_free(doc); + throw SerializationException("Could not parse PROJJSON CRS for GeoArrow metadata"); + } + } break; + case CoordinateReferenceSystemType::AUTH_CODE: { + duckdb_yyjson::yyjson_mut_obj_add_str(doc, root, "crs_type", "authority_code"); + duckdb_yyjson::yyjson_mut_obj_add_str(doc, root, "crs", crs_def.c_str()); + } break; + case CoordinateReferenceSystemType::SRID: { + duckdb_yyjson::yyjson_mut_obj_add_str(doc, root, "crs_type", "srid"); + duckdb_yyjson::yyjson_mut_obj_add_str(doc, root, "crs", crs_def.c_str()); + } break; + case CoordinateReferenceSystemType::WKT2_2019: { + duckdb_yyjson::yyjson_mut_obj_add_str(doc, root, "crs_type", "wkt2:2019"); + duckdb_yyjson::yyjson_mut_obj_add_str(doc, root, "crs", crs_def.c_str()); + } break; + default: + throw SerializationException("Could not serialize CRS of type %d for GeoArrow metadata", + static_cast(crs.GetType())); + } + } + static void PopulateSchema(DuckDBArrowSchemaHolder &root_holder, ArrowSchema &schema, const LogicalType &type, ClientContext &context, const ArrowTypeExtension &extension) { ArrowSchemaMetadata schema_metadata; + schema_metadata.AddOption(ArrowSchemaMetadata::ARROW_EXTENSION_NAME, "geoarrow.wkb"); - schema_metadata.AddOption(ArrowSchemaMetadata::ARROW_METADATA_KEY, "{}"); + + // Make a CRS entry if the type has a CRS + const auto doc = duckdb_yyjson::yyjson_mut_doc_new(nullptr); + const auto root = duckdb_yyjson::yyjson_mut_obj(doc); + duckdb_yyjson::yyjson_mut_doc_set_root(doc, root); + + if (GeoType::HasCRS(type)) { + try { + WriteCRS(doc, GeoType::GetCRS(type), context); + } catch (...) { + duckdb_yyjson::yyjson_mut_doc_free(doc); + throw; + } + } + + size_t json_size = 0; + const auto json_text = duckdb_yyjson::yyjson_mut_write(doc, duckdb_yyjson::YYJSON_WRITE_NOFLAG, &json_size); + if (json_text) { + schema_metadata.AddOption(ArrowSchemaMetadata::ARROW_METADATA_KEY, json_text); + duckdb_yyjson::yyjson_mut_doc_free(doc); + free(json_text); + } else { + schema_metadata.AddOption(ArrowSchemaMetadata::ARROW_METADATA_KEY, "{}"); + } + root_holder.metadata_info.emplace_back(schema_metadata.SerializeMetadata()); schema.metadata = root_holder.metadata_info.back().get(); diff --git a/src/duckdb/src/common/box_renderer.cpp b/src/duckdb/src/common/box_renderer.cpp index b76721596..861d59c14 100644 --- a/src/duckdb/src/common/box_renderer.cpp +++ b/src/duckdb/src/common/box_renderer.cpp @@ -205,7 +205,7 @@ struct BoxRendererImplementation : public BoxRendererState { void RenderValue(BaseResultRenderer &ss, const string &value, idx_t column_width, ResultRenderType render_mode, const vector &annotations, ValueRenderAlignment alignment = ValueRenderAlignment::MIDDLE, - optional_idx render_width = optional_idx()); + optional_idx render_width = optional_idx(), const char *vertical = nullptr); string RenderType(const LogicalType &type); ValueRenderAlignment TypeAlignment(const LogicalType &type); void ConvertRenderVector(Vector &vector, Vector &render_lengths, idx_t count, const LogicalType &original_type, @@ -263,9 +263,10 @@ void BoxRendererImplementation::ComputeRowFooter(idx_t row_count, idx_t rendered footer.row_count_str = "? rows"; } if (config.large_number_rendering == LargeNumberRendering::FOOTER && !has_limited_rows) { - footer.readable_rows_str = TryFormatLargeNumber(to_string(row_count)); - if (!footer.readable_rows_str.empty()) { - footer.readable_rows_str += " rows"; + string readable_str = TryFormatLargeNumber(to_string(row_count)); + if (!readable_str.empty()) { + footer.readable_rows_str = to_string(row_count) + " total"; + footer.row_count_str = readable_str + " rows"; } } footer.has_hidden_rows = rendered_rows < row_count; @@ -412,7 +413,8 @@ string BoxRendererImplementation::TruncateValue(const string &value, idx_t colum void BoxRendererImplementation::RenderValue(BaseResultRenderer &ss, const string &value, idx_t column_width, ResultRenderType render_mode, const vector &annotations, - ValueRenderAlignment alignment, optional_idx render_width_input) { + ValueRenderAlignment alignment, optional_idx render_width_input, + const char *vertical) { idx_t render_width; if (render_width_input.IsValid()) { render_width = render_width_input.GetIndex(); @@ -457,7 +459,7 @@ void BoxRendererImplementation::RenderValue(BaseResultRenderer &ss, const string default: throw InternalException("Unrecognized value renderer alignment"); } - ss << config.VERTICAL; + ss << (vertical ? vertical : config.VERTICAL); ss << string(lpadding, ' '); if (!annotations.empty()) { // if we have annotations split up the rendering between annotations @@ -2127,7 +2129,7 @@ void BoxRendererImplementation::RenderValues(BaseResultRenderer &ss, vector= shown_size) { // we have space - render it here extra_render_str = " ("; + extra_render_str += shown_str; if (!readable_rows_str.empty()) { - extra_render_str += readable_rows_str + ", "; + extra_render_str += ", " + readable_rows_str; } - extra_render_str += shown_str; extra_render_str += ")"; D_ASSERT(extra_render_str.size() == shown_size); padding -= shown_size; @@ -2208,14 +2209,26 @@ void BoxRendererImplementation::RenderFooter(BaseResultRenderer &ss, idx_t row_c shown_str = string(); } - ss << config.VERTICAL; - ss << " "; + ss << " "; if (render_rows_and_columns) { ss.Render(ResultRenderType::FOOTER, row_count_str); if (!extra_render_str.empty()) { - ss.Render(ResultRenderType::NULL_VALUE, extra_render_str); + ss.Render(ResultRenderType::FOOTER, extra_render_str); + } + // can we add the hidden rows hint to this line? + if ((has_hidden_columns || has_hidden_rows) && !config.hidden_rows_hint.empty() && + padding >= config.hidden_rows_hint.size() + 10) { + // we can + padding -= config.hidden_rows_hint.size(); + auto lpadding = padding / 2; + auto rpadding = padding - lpadding; + ss << string(lpadding, ' '); + ss.Render(ResultRenderType::FOOTER, config.hidden_rows_hint); + ss << string(rpadding, ' '); + } else { + // we can't - don't render it + ss << string(padding, ' '); } - ss << string(padding, ' '); ss.Render(ResultRenderType::FOOTER, column_count_str); } else if (render_rows) { idx_t lpadding = padding / 2; @@ -2223,12 +2236,10 @@ void BoxRendererImplementation::RenderFooter(BaseResultRenderer &ss, idx_t row_c ss << string(lpadding, ' '); ss.Render(ResultRenderType::FOOTER, row_count_str); if (!extra_render_str.empty()) { - ss.Render(ResultRenderType::NULL_VALUE, extra_render_str); + ss.Render(ResultRenderType::FOOTER, extra_render_str); } ss << string(rpadding, ' '); } - ss << " "; - ss << config.VERTICAL; ss << '\n'; if (!readable_rows_str.empty() || !shown_str.empty()) { // we still need to render the readable rows/shown strings @@ -2236,13 +2247,10 @@ void BoxRendererImplementation::RenderFooter(BaseResultRenderer &ss, idx_t row_c idx_t combined_shown_length = readable_rows_str.size() + shown_str.size() + 4; if (!readable_rows_str.empty() && !shown_str.empty() && combined_shown_length <= total_render_length) { // we can! merge them - ss << config.VERTICAL; - ss << " "; - ss.Render(ResultRenderType::NULL_VALUE, readable_rows_str); + ss << " "; + ss.Render(ResultRenderType::FOOTER, shown_str); ss << string(total_render_length - combined_shown_length, ' '); - ss.Render(ResultRenderType::NULL_VALUE, shown_str); - ss << " "; - ss << config.VERTICAL; + ss.Render(ResultRenderType::FOOTER, readable_rows_str); ss << '\n'; readable_rows_str = string(); shown_str = string(); @@ -2250,21 +2258,17 @@ void BoxRendererImplementation::RenderFooter(BaseResultRenderer &ss, idx_t row_c ValueRenderAlignment alignment = render_rows_and_columns ? ValueRenderAlignment::LEFT : ValueRenderAlignment::MIDDLE; vector annotations; - if (!readable_rows_str.empty()) { - RenderValue(ss, "(" + readable_rows_str + ")", total_render_length - 4, ResultRenderType::NULL_VALUE, - annotations, alignment); - ss << config.VERTICAL; + if (!shown_str.empty()) { + RenderValue(ss, "(" + shown_str + ")", total_render_length - 4, ResultRenderType::FOOTER, annotations, + alignment, optional_idx(), " "); ss << '\n'; } - if (!shown_str.empty()) { - RenderValue(ss, "(" + shown_str + ")", total_render_length - 4, ResultRenderType::NULL_VALUE, annotations, - alignment); - ss << config.VERTICAL; + if (!readable_rows_str.empty()) { + RenderValue(ss, "(" + readable_rows_str + ")", total_render_length - 4, ResultRenderType::FOOTER, + annotations, alignment, optional_idx(), " "); ss << '\n'; } } - // render the bottom line - RenderLayoutLine(ss, config.HORIZONTAL, config.HORIZONTAL, config.LDCORNER, config.RDCORNER); } //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/common/csv_writer.cpp b/src/duckdb/src/common/csv_writer.cpp index 8f8992347..2cac613a3 100644 --- a/src/duckdb/src/common/csv_writer.cpp +++ b/src/duckdb/src/common/csv_writer.cpp @@ -227,6 +227,9 @@ void CSVWriter::WriteQuoteOrEscape(WriteStream &writer, char quote_or_escape) { } string CSVWriter::AddEscapes(char to_be_escaped, char escape, const string &val) { + if (escape == '\0') { + return val; + } idx_t i = 0; string new_val = ""; idx_t found = val.find(to_be_escaped); @@ -236,10 +239,8 @@ string CSVWriter::AddEscapes(char to_be_escaped, char escape, const string &val) new_val += val[i]; i++; } - if (escape != '\0') { - new_val += escape; - found = val.find(to_be_escaped, found + 1); - } + new_val += escape; + found = val.find(to_be_escaped, found + 1); } while (i < val.length()) { new_val += val[i]; diff --git a/src/duckdb/src/common/encryption_functions.cpp b/src/duckdb/src/common/encryption_functions.cpp index 262ff3c14..3f612c2f0 100644 --- a/src/duckdb/src/common/encryption_functions.cpp +++ b/src/duckdb/src/common/encryption_functions.cpp @@ -1,36 +1,14 @@ #include "duckdb/common/exception/conversion_exception.hpp" #include "duckdb/common/encryption_key_manager.hpp" #include "duckdb/common/encryption_functions.hpp" -#include "duckdb/common/serializer/memory_stream.hpp" #include "duckdb/main/attached_database.hpp" #include "mbedtls_wrapper.hpp" #include "duckdb/storage/storage_manager.hpp" #include "duckdb/storage/storage_info.hpp" +#include "duckdb/common/typedefs.hpp" namespace duckdb { -EncryptionTag::EncryptionTag() : tag(new data_t[MainHeader::AES_TAG_LEN]) { -} - -data_ptr_t EncryptionTag::data() { - return tag.get(); -} - -idx_t EncryptionTag::size() const { - return MainHeader::AES_TAG_LEN; -} - -EncryptionNonce::EncryptionNonce() : nonce(new data_t[MainHeader::AES_NONCE_LEN]) { -} - -data_ptr_t EncryptionNonce::data() { - return nonce.get(); -} - -idx_t EncryptionNonce::size() const { - return MainHeader::AES_NONCE_LEN; -} - constexpr uint32_t AdditionalAuthenticatedData::INITIAL_AAD_CAPACITY; AdditionalAuthenticatedData::~AdditionalAuthenticatedData() = default; @@ -50,6 +28,9 @@ void AdditionalAuthenticatedData::WriteStringData(const std::string &val) const EncryptionEngine::EncryptionEngine() { } +EncryptionEngine::~EncryptionEngine() { +} + const_data_ptr_t EncryptionEngine::GetKeyFromCache(DatabaseInstance &db, const string &key_name) { auto &keys = EncryptionKeyManager::Get(db); return keys.GetKey(key_name); @@ -65,8 +46,8 @@ void EncryptionEngine::AddKeyToCache(DatabaseInstance &db, data_ptr_t key, const if (!keys.HasKey(key_name)) { keys.AddKey(key_name, key); } else { - // wipe out the key - std::memset(key, 0, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + duckdb_mbedtls::MbedTlsWrapper::AESStateMBEDTLS::SecureClearData(key, + MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); } } @@ -77,8 +58,8 @@ string EncryptionEngine::AddKeyToCache(DatabaseInstance &db, data_ptr_t key) { if (!keys.HasKey(key_id)) { keys.AddKey(key_id, key); } else { - // wipe out the original key - std::memset(key, 0, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + duckdb_mbedtls::MbedTlsWrapper::AESStateMBEDTLS::SecureClearData(key, + MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); } return key_id; @@ -89,8 +70,9 @@ void EncryptionEngine::AddTempKeyToCache(DatabaseInstance &db) { const auto length = MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH; data_t temp_key[length]; - auto encryption_state = db.GetEncryptionUtil()->CreateEncryptionState( - /* only for random generator */ EncryptionTypes::GCM, length); + // we cannot generate temporary keys with read-only enabled + auto metadata = make_uniq(EncryptionTypes::GCM, length, EncryptionTypes::V0_1); + auto encryption_state = db.GetEncryptionUtil(false)->CreateEncryptionState(std::move(metadata)); encryption_state->GenerateRandomData(temp_key, length); string key_id = "temp_key"; @@ -102,17 +84,18 @@ void EncryptionEngine::EncryptBlock(AttachedDatabase &attached_db, const string auto &db = attached_db.GetDatabase(); data_ptr_t block_offset_internal = temp_buffer_manager.InternalBuffer(); auto encrypt_key = GetKeyFromCache(db, key_id); - auto encryption_state = db.GetEncryptionUtil()->CreateEncryptionState(attached_db.GetStorageManager().GetCipher(), - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + auto version = attached_db.GetStorageManager().GetEncryptionVersion(); + auto cipher = attached_db.GetStorageManager().GetCipher(); + auto metadata = make_uniq(cipher, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, version); + auto encryption_state = db.GetEncryptionUtil(attached_db.IsReadOnly())->CreateEncryptionState(std::move(metadata)); EncryptionTag tag; - EncryptionNonce nonce; + EncryptionNonce nonce(cipher, version); encryption_state->GenerateRandomData(nonce.data(), nonce.size()); //! store the nonce at the start of the block memcpy(block_offset_internal, nonce.data(), nonce.size()); - encryption_state->InitializeEncryption(nonce.data(), nonce.size(), encrypt_key, - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + encryption_state->InitializeEncryption(nonce, encrypt_key); auto checksum_offset = block.InternalBuffer() + delta; auto encryption_checksum_offset = block_offset_internal + delta; @@ -136,20 +119,20 @@ void EncryptionEngine::DecryptBlock(AttachedDatabase &attached_db, const string uint64_t block_size, uint64_t delta) { //! initialize encryption state auto &db = attached_db.GetDatabase(); - + auto version = attached_db.GetStorageManager().GetEncryptionVersion(); + auto cipher = attached_db.GetStorageManager().GetCipher(); + auto metadata = make_uniq(cipher, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, version); auto decrypt_key = GetKeyFromCache(db, key_id); - auto encryption_state = db.GetEncryptionUtil()->CreateEncryptionState(attached_db.GetStorageManager().GetCipher(), - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + auto encryption_state = db.GetEncryptionUtil(attached_db.IsReadOnly())->CreateEncryptionState(std::move(metadata)); //! load the stored nonce and tag EncryptionTag tag; - EncryptionNonce nonce; + EncryptionNonce nonce(cipher, version); memcpy(nonce.data(), internal_buffer, nonce.size()); memcpy(tag.data(), internal_buffer + nonce.size(), tag.size()); //! Initialize the decryption - encryption_state->InitializeDecryption(nonce.data(), nonce.size(), decrypt_key, - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + encryption_state->InitializeDecryption(nonce, decrypt_key); auto checksum_offset = internal_buffer + delta; auto size = block_size + Storage::DEFAULT_BLOCK_HEADER_SIZE; @@ -172,25 +155,24 @@ void EncryptionEngine::EncryptTemporaryBuffer(DatabaseInstance &db, data_ptr_t b } auto temp_key = GetKeyFromCache(db, "temp_key"); - - auto encryption_util = db.GetEncryptionUtil(); + // we cannot encrypt temp buffers in read-only mode + auto encryption_util = db.GetEncryptionUtil(false); // we hard-code GCM here for now, it's the safest and we don't know what is configured here - auto encryption_state = - encryption_util->CreateEncryptionState(EncryptionTypes::GCM, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + auto state_metadata = make_uniq( + EncryptionTypes::GCM, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, EncryptionTypes::V0_1); + auto encryption_state = encryption_util->CreateEncryptionState(std::move(state_metadata)); // zero-out the metadata buffer memset(metadata, 0, DEFAULT_ENCRYPTED_BUFFER_HEADER_SIZE); EncryptionTag tag; - EncryptionNonce nonce; + EncryptionNonce nonce(EncryptionTypes::CipherType::GCM, EncryptionTypes::V0_1); encryption_state->GenerateRandomData(nonce.data(), nonce.size()); //! store the nonce at the start of metadata buffer memcpy(metadata, nonce.data(), nonce.size()); - - encryption_state->InitializeEncryption(nonce.data(), nonce.size(), temp_key, - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + encryption_state->InitializeEncryption(nonce, temp_key); auto aes_res = encryption_state->Process(buffer, buffer_size, buffer, buffer_size); @@ -213,13 +195,12 @@ static void DecryptBuffer(EncryptionState &encryption_state, const_data_ptr_t te idx_t buffer_size, data_ptr_t metadata) { //! load the stored nonce and tag EncryptionTag tag; - EncryptionNonce nonce; + EncryptionNonce nonce(encryption_state.metadata->GetCipher(), encryption_state.metadata->GetVersion()); memcpy(nonce.data(), metadata, nonce.size()); memcpy(tag.data(), metadata + nonce.size(), tag.size()); //! Initialize the decryption - encryption_state.InitializeDecryption(nonce.data(), nonce.size(), temp_key, - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + encryption_state.InitializeDecryption(nonce, temp_key); auto aes_res = encryption_state.Process(buffer, buffer_size, buffer, buffer_size); @@ -234,10 +215,11 @@ static void DecryptBuffer(EncryptionState &encryption_state, const_data_ptr_t te void EncryptionEngine::DecryptTemporaryBuffer(DatabaseInstance &db, data_ptr_t buffer, idx_t buffer_size, data_ptr_t metadata) { //! initialize encryption state - auto encryption_util = db.GetEncryptionUtil(); + auto encryption_util = db.GetEncryptionUtil(false); auto temp_key = GetKeyFromCache(db, "temp_key"); - auto encryption_state = - encryption_util->CreateEncryptionState(EncryptionTypes::GCM, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + auto state_metadata = make_uniq( + EncryptionTypes::GCM, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, EncryptionTypes::EncryptionVersion::V0_1); + auto encryption_state = encryption_util->CreateEncryptionState(std::move(state_metadata)); DecryptBuffer(*encryption_state, temp_key, buffer, buffer_size, metadata); } diff --git a/src/duckdb/src/common/encryption_key_manager.cpp b/src/duckdb/src/common/encryption_key_manager.cpp index 409fe605c..4d174525b 100644 --- a/src/duckdb/src/common/encryption_key_manager.cpp +++ b/src/duckdb/src/common/encryption_key_manager.cpp @@ -75,7 +75,7 @@ string EncryptionKeyManager::GenerateRandomKeyID() { void EncryptionKeyManager::AddKey(const string &key_name, data_ptr_t key) { lock_guard guard(lock); derived_keys.emplace(key_name, EncryptionKey(key)); - // Zero-out the encryption key + // Zero-out the input encryption key duckdb_mbedtls::MbedTlsWrapper::AESStateMBEDTLS::SecureClearData(key, DERIVED_KEY_LENGTH); } @@ -92,6 +92,19 @@ const_data_ptr_t EncryptionKeyManager::GetKey(const string &key_name) const { void EncryptionKeyManager::DeleteKey(const string &key_name) { lock_guard guard(lock); + ClearKey(key_name); + EraseKey(key_name); +} + +void EncryptionKeyManager::ClearKey(const string &key_name) { + D_ASSERT(HasKey(key_name)); + auto const key_data = derived_keys.at(key_name).GetData(); + // clear the key (zero-out its memory) + duckdb_mbedtls::MbedTlsWrapper::AESStateMBEDTLS::SecureClearData(key_data, + MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); +} + +void EncryptionKeyManager::EraseKey(const string &key_name) { derived_keys.erase(key_name); } @@ -131,6 +144,7 @@ void EncryptionKeyManager::DeriveKey(string &user_key, data_ptr_t salt, data_ptr KeyDerivationFunctionSHA256(reinterpret_cast(decoded_key.data()), decoded_key.size(), salt, derived_key); + duckdb_mbedtls::MbedTlsWrapper::AESStateMBEDTLS::SecureClearData(data_ptr_cast(&user_key[0]), user_key.size()); duckdb_mbedtls::MbedTlsWrapper::AESStateMBEDTLS::SecureClearData(data_ptr_cast(&decoded_key[0]), decoded_key.size()); diff --git a/src/duckdb/src/common/encryption_state.cpp b/src/duckdb/src/common/encryption_state.cpp index 0763bc5a6..a63bd9456 100644 --- a/src/duckdb/src/common/encryption_state.cpp +++ b/src/duckdb/src/common/encryption_state.cpp @@ -2,18 +2,17 @@ namespace duckdb { -EncryptionState::EncryptionState(EncryptionTypes::CipherType cipher_p, idx_t key_len_p) - : cipher(cipher_p), key_len(key_len_p) { +EncryptionState::EncryptionState(unique_ptr metadata_p) : metadata(std::move(metadata_p)) { } EncryptionState::~EncryptionState() { } -void EncryptionState::InitializeEncryption(const_data_ptr_t, idx_t, const_data_ptr_t, idx_t, const_data_ptr_t, idx_t) { +void EncryptionState::InitializeEncryption(EncryptionNonce &nonce, const_data_ptr_t, const_data_ptr_t, idx_t) { throw NotImplementedException("EncryptionState Abstract Class is called"); } -void EncryptionState::InitializeDecryption(const_data_ptr_t, idx_t, const_data_ptr_t, idx_t, const_data_ptr_t, idx_t) { +void EncryptionState::InitializeDecryption(EncryptionNonce &nonce, const_data_ptr_t, const_data_ptr_t, idx_t) { throw NotImplementedException("EncryptionState Abstract Class is called"); } @@ -29,53 +28,4 @@ void EncryptionState::GenerateRandomData(data_ptr_t, idx_t) { throw NotImplementedException("EncryptionState Abstract Class is called"); } -string EncryptionTypes::CipherToString(CipherType cipher_p) { - switch (cipher_p) { - case GCM: - return "GCM"; - case CTR: - return "CTR"; - case CBC: - return "CBC"; - default: - return "INVALID"; - } -} - -EncryptionTypes::CipherType EncryptionTypes::StringToCipher(const string &encryption_cipher_p) { - auto encryption_cipher = StringUtil::Upper(encryption_cipher_p); - if (encryption_cipher == "GCM") { - return GCM; - } - if (encryption_cipher == "CTR") { - return CTR; - } - if (encryption_cipher == "CBC") { - throw NotImplementedException("CBC encryption is disabled"); - } - return INVALID; -} - -string EncryptionTypes::KDFToString(KeyDerivationFunction kdf_p) { - switch (kdf_p) { - case SHA256: - return "SHA256"; - case PBKDF2: - return "PBKDF2"; - default: - return "DEFAULT"; - } -} - -EncryptionTypes::KeyDerivationFunction EncryptionTypes::StringToKDF(const string &key_derivation_function_p) { - auto key_derivation_function = StringUtil::Upper(key_derivation_function_p); - if (key_derivation_function == "SHA256") { - return SHA256; - } - if (key_derivation_function == "PBKDF2") { - return PBKDF2; - } - return DEFAULT; -} - } // namespace duckdb diff --git a/src/duckdb/src/common/encryption_types.cpp b/src/duckdb/src/common/encryption_types.cpp new file mode 100644 index 000000000..4b23e9c77 --- /dev/null +++ b/src/duckdb/src/common/encryption_types.cpp @@ -0,0 +1,178 @@ +#include "duckdb/common/encryption_types.hpp" + +namespace duckdb { + +static constexpr EncryptionTypes::EncryptionVersion MAX_VERSION = EncryptionTypes::V0_1; + +string EncryptionTypes::CipherToString(CipherType cipher_p) { + switch (cipher_p) { + case GCM: + return "GCM"; + case CTR: + return "CTR"; + case CBC: + return "CBC"; + default: + return "INVALID"; + } +} + +EncryptionTypes::CipherType EncryptionTypes::StringToCipher(const string &encryption_cipher_p) { + auto encryption_cipher = StringUtil::Upper(encryption_cipher_p); + if (encryption_cipher == "GCM") { + return GCM; + } + if (encryption_cipher == "CTR") { + return CTR; + } + if (encryption_cipher == "CBC") { + throw NotImplementedException("CBC encryption is disabled"); + } + return INVALID; +} + +EncryptionTypes::EncryptionVersion EncryptionTypes::StringToVersion(const string &encryption_version_p) { + if (encryption_version_p == "v0") { + return V0_0; + } else if (encryption_version_p == "v1") { + return V0_1; + } else { + throw NotImplementedException("No encryption version higher then v%d is supported yet in this DuckDB version", + MAX_VERSION); + } +} + +string EncryptionTypes::KDFToString(KeyDerivationFunction kdf_p) { + switch (kdf_p) { + case SHA256: + return "SHA256"; + case PBKDF2: + return "PBKDF2"; + default: + return "DEFAULT"; + } +} + +EncryptionTypes::KeyDerivationFunction EncryptionTypes::StringToKDF(const string &key_derivation_function_p) { + auto key_derivation_function = StringUtil::Upper(key_derivation_function_p); + if (key_derivation_function == "SHA256") { + return SHA256; + } + if (key_derivation_function == "PBKDF2") { + return PBKDF2; + } + return DEFAULT; +} + +using CipherType = EncryptionTypes::CipherType; +using Version = EncryptionTypes::EncryptionVersion; + +EncryptionTag::EncryptionTag() : tag(new data_t[MainHeader::AES_TAG_LEN]()) { + tag_len = MainHeader::AES_TAG_LEN; +} + +data_ptr_t EncryptionTag::data() { + return tag.get(); +} + +idx_t EncryptionTag::size() const { + return tag_len; +} + +bool EncryptionTag::IsAllZeros() const { + auto tag_ptr = tag.get(); + idx_t len = size(); + + data_t is_only_zero = 0; + for (idx_t i = 0; i < len; ++i) { + is_only_zero |= tag_ptr[i]; + } + return is_only_zero == 0; +} + +void EncryptionTag::SetSize(idx_t size) { + tag_len = size; +} + +EncryptionCanary::EncryptionCanary() : canary(new data_t[MainHeader::CANARY_BYTE_SIZE]()) { +#ifdef DEBUG + // Check whether canary is zero-initialized + for (idx_t i = 0; i < MainHeader::CANARY_BYTE_SIZE; i++) { + if (canary[i] != 0) { + throw InvalidInputException("Nonce is not correctly zero-initialized!"); + } + } +#endif +} + +data_ptr_t EncryptionCanary::data() { + return canary.get(); +} + +idx_t EncryptionCanary::size() const { + return MainHeader::CANARY_BYTE_SIZE; +} + +EncryptionNonce::EncryptionNonce(CipherType cipher_p, Version version_p) : version(version_p), cipher(cipher_p) { + switch (version) { + case Version::V0_0: + // for prior versions + // nonce len is 16 for both GCM and CTR + nonce_len = MainHeader::AES_NONCE_LEN_DEPRECATED; + nonce = unique_ptr(new data_t[nonce_len]()); + break; + case Version::V0_1: + if (cipher == CipherType::CTR) { + // for CTR we need a 16-byte nonce / iv + // the last 4 bytes (counter) are zeroed-out + nonce_len = MainHeader::AES_IV_LEN; + nonce = unique_ptr(new data_t[nonce_len]()); + break; + } + // we fall through to NONE (often Parquet) with a 12-byte nonce + DUCKDB_EXPLICIT_FALLTHROUGH; + case Version::NONE: + nonce_len = MainHeader::AES_NONCE_LEN; + nonce = unique_ptr(new data_t[nonce_len]()); + break; + default: + throw InvalidConfigurationException("Encryption version not recognized!"); + } + +#ifdef DEBUG + // Check whether the nonce is zero-initialized + for (idx_t i = 0; i < nonce_len; i++) { + if (nonce[i] != 0) { + throw InvalidInputException("Nonce is not correctly zero-initialized!"); + } + } +#endif +} + +data_ptr_t EncryptionNonce::data() { + return nonce.get(); +} + +idx_t EncryptionNonce::size() const { + // always return 12 bytes + if (version == Version::V0_0) { + // in the first version, nonce was always 16 + return MainHeader::AES_NONCE_LEN_DEPRECATED; + } + // in v1, nonce is always 12 + return MainHeader::AES_NONCE_LEN; +} + +idx_t EncryptionNonce::total_size() const { + return nonce_len; +} + +idx_t EncryptionNonce::size_deprecated() const { + return MainHeader::AES_NONCE_LEN_DEPRECATED; +} + +void EncryptionNonce::SetSize(idx_t length) { + nonce_len = length; +} + +} // namespace duckdb diff --git a/src/duckdb/src/common/enum_util.cpp b/src/duckdb/src/common/enum_util.cpp index 9e04cf913..522a2422c 100644 --- a/src/duckdb/src/common/enum_util.cpp +++ b/src/duckdb/src/common/enum_util.cpp @@ -16,6 +16,7 @@ #include "duckdb/common/column_index.hpp" #include "duckdb/common/enums/access_mode.hpp" #include "duckdb/common/enums/aggregate_handling.hpp" +#include "duckdb/common/enums/allow_parser_override.hpp" #include "duckdb/common/enums/arrow_format_version.hpp" #include "duckdb/common/enums/cache_validation_mode.hpp" #include "duckdb/common/enums/catalog_lookup_behavior.hpp" @@ -27,6 +28,7 @@ #include "duckdb/common/enums/date_part_specifier.hpp" #include "duckdb/common/enums/debug_initialize.hpp" #include "duckdb/common/enums/debug_vector_verification.hpp" +#include "duckdb/common/enums/deprecated_using_key_syntax.hpp" #include "duckdb/common/enums/destroy_buffer_upon.hpp" #include "duckdb/common/enums/explain_format.hpp" #include "duckdb/common/enums/expression_type.hpp" @@ -38,6 +40,7 @@ #include "duckdb/common/enums/index_constraint_type.hpp" #include "duckdb/common/enums/join_type.hpp" #include "duckdb/common/enums/joinref_type.hpp" +#include "duckdb/common/enums/lambda_syntax.hpp" #include "duckdb/common/enums/logical_operator_type.hpp" #include "duckdb/common/enums/memory_tag.hpp" #include "duckdb/common/enums/merge_action_type.hpp" @@ -102,6 +105,7 @@ #include "duckdb/common/types/vector_buffer.hpp" #include "duckdb/execution/index/art/art.hpp" #include "duckdb/execution/index/art/art_scanner.hpp" +#include "duckdb/execution/index/art/iterator.hpp" #include "duckdb/execution/index/art/node.hpp" #include "duckdb/execution/index/bound_index.hpp" #include "duckdb/execution/index/unbound_index.hpp" @@ -172,7 +176,7 @@ #include "duckdb/planner/binder.hpp" #include "duckdb/planner/bound_result_modifier.hpp" #include "duckdb/planner/table_filter.hpp" -#include "duckdb/storage/buffer/block_handle.hpp" +#include "duckdb/storage/buffer/buffer_pool_reservation.hpp" #include "duckdb/storage/caching_mode.hpp" #include "duckdb/storage/compression/bitpacking.hpp" #include "duckdb/storage/magic_bytes.hpp" @@ -180,7 +184,9 @@ #include "duckdb/storage/statistics/variant_stats.hpp" #include "duckdb/storage/storage_index.hpp" #include "duckdb/storage/table/chunk_info.hpp" +#include "duckdb/storage/table/column_data.hpp" #include "duckdb/storage/table/column_segment.hpp" +#include "duckdb/storage/table/row_group_reorderer.hpp" #include "duckdb/storage/table/table_index_list.hpp" #include "duckdb/storage/temporary_file_manager.hpp" #include "duckdb/verification/statement_verifier.hpp" @@ -244,6 +250,24 @@ ARTScanHandling EnumUtil::FromString(const char *value) { return static_cast(StringUtil::StringToEnum(GetARTScanHandlingValues(), 2, "ARTScanHandling", value)); } +const StringUtil::EnumStringLiteral *GetARTScanResultValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ARTScanResult::COMPLETED), "COMPLETED" }, + { static_cast(ARTScanResult::PAUSED), "PAUSED" } + }; + return values; +} + +template<> +const char* EnumUtil::ToChars(ARTScanResult value) { + return StringUtil::EnumToString(GetARTScanResultValues(), 2, "ARTScanResult", static_cast(value)); +} + +template<> +ARTScanResult EnumUtil::FromString(const char *value) { + return static_cast(StringUtil::StringToEnum(GetARTScanResultValues(), 2, "ARTScanResult", value)); +} + const StringUtil::EnumStringLiteral *GetAccessModeValues() { static constexpr StringUtil::EnumStringLiteral values[] { { static_cast(AccessMode::UNDEFINED), "UNDEFINED" }, @@ -355,6 +379,26 @@ AggregateType EnumUtil::FromString(const char *value) { return static_cast(StringUtil::StringToEnum(GetAggregateTypeValues(), 2, "AggregateType", value)); } +const StringUtil::EnumStringLiteral *GetAllowParserOverrideValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AllowParserOverride::DEFAULT_OVERRIDE), "DEFAULT" }, + { static_cast(AllowParserOverride::FALLBACK_OVERRIDE), "FALLBACK" }, + { static_cast(AllowParserOverride::STRICT_OVERRIDE), "STRICT" }, + { static_cast(AllowParserOverride::STRICT_WHEN_SUPPORTED), "STRICT_WHEN_SUPPORTED" } + }; + return values; +} + +template<> +const char* EnumUtil::ToChars(AllowParserOverride value) { + return StringUtil::EnumToString(GetAllowParserOverrideValues(), 4, "AllowParserOverride", static_cast(value)); +} + +template<> +AllowParserOverride EnumUtil::FromString(const char *value) { + return static_cast(StringUtil::StringToEnum(GetAllowParserOverrideValues(), 4, "AllowParserOverride", value)); +} + const StringUtil::EnumStringLiteral *GetAlterDatabaseTypeValues() { static constexpr StringUtil::EnumStringLiteral values[] { { static_cast(AlterDatabaseType::RENAME_DATABASE), "RENAME_DATABASE" } @@ -444,19 +488,21 @@ const StringUtil::EnumStringLiteral *GetAlterTableTypeValues() { { static_cast(AlterTableType::SET_SORTED_BY), "SET_SORTED_BY" }, { static_cast(AlterTableType::ADD_FIELD), "ADD_FIELD" }, { static_cast(AlterTableType::REMOVE_FIELD), "REMOVE_FIELD" }, - { static_cast(AlterTableType::RENAME_FIELD), "RENAME_FIELD" } + { static_cast(AlterTableType::RENAME_FIELD), "RENAME_FIELD" }, + { static_cast(AlterTableType::SET_TABLE_OPTIONS), "SET_TABLE_OPTIONS" }, + { static_cast(AlterTableType::RESET_TABLE_OPTIONS), "RESET_TABLE_OPTIONS" } }; return values; } template<> const char* EnumUtil::ToChars(AlterTableType value) { - return StringUtil::EnumToString(GetAlterTableTypeValues(), 17, "AlterTableType", static_cast(value)); + return StringUtil::EnumToString(GetAlterTableTypeValues(), 19, "AlterTableType", static_cast(value)); } template<> AlterTableType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAlterTableTypeValues(), 17, "AlterTableType", value)); + return static_cast(StringUtil::StringToEnum(GetAlterTableTypeValues(), 19, "AlterTableType", value)); } const StringUtil::EnumStringLiteral *GetAlterTypeValues() { @@ -959,6 +1005,7 @@ const StringUtil::EnumStringLiteral *GetCatalogTypeValues() { { static_cast(CatalogType::COLLATION_ENTRY), "COLLATION_ENTRY" }, { static_cast(CatalogType::TYPE_ENTRY), "TYPE_ENTRY" }, { static_cast(CatalogType::DATABASE_ENTRY), "DATABASE_ENTRY" }, + { static_cast(CatalogType::COORDINATE_SYSTEM_ENTRY), "COORDINATE_SYSTEM_ENTRY" }, { static_cast(CatalogType::TABLE_FUNCTION_ENTRY), "TABLE_FUNCTION_ENTRY" }, { static_cast(CatalogType::SCALAR_FUNCTION_ENTRY), "SCALAR_FUNCTION_ENTRY" }, { static_cast(CatalogType::AGGREGATE_FUNCTION_ENTRY), "AGGREGATE_FUNCTION_ENTRY" }, @@ -978,12 +1025,12 @@ const StringUtil::EnumStringLiteral *GetCatalogTypeValues() { template<> const char* EnumUtil::ToChars(CatalogType value) { - return StringUtil::EnumToString(GetCatalogTypeValues(), 23, "CatalogType", static_cast(value)); + return StringUtil::EnumToString(GetCatalogTypeValues(), 24, "CatalogType", static_cast(value)); } template<> CatalogType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCatalogTypeValues(), 23, "CatalogType", value)); + return static_cast(StringUtil::StringToEnum(GetCatalogTypeValues(), 24, "CatalogType", value)); } const StringUtil::EnumStringLiteral *GetCheckpointAbortValues() { @@ -1124,22 +1171,22 @@ CompressedMaterializationDirection EnumUtil::FromString(CompressionType::COMPRESSION_AUTO), "COMPRESSION_AUTO" }, - { static_cast(CompressionType::COMPRESSION_UNCOMPRESSED), "COMPRESSION_UNCOMPRESSED" }, - { static_cast(CompressionType::COMPRESSION_CONSTANT), "COMPRESSION_CONSTANT" }, - { static_cast(CompressionType::COMPRESSION_RLE), "COMPRESSION_RLE" }, - { static_cast(CompressionType::COMPRESSION_DICTIONARY), "COMPRESSION_DICTIONARY" }, - { static_cast(CompressionType::COMPRESSION_PFOR_DELTA), "COMPRESSION_PFOR_DELTA" }, - { static_cast(CompressionType::COMPRESSION_BITPACKING), "COMPRESSION_BITPACKING" }, - { static_cast(CompressionType::COMPRESSION_FSST), "COMPRESSION_FSST" }, - { static_cast(CompressionType::COMPRESSION_CHIMP), "COMPRESSION_CHIMP" }, - { static_cast(CompressionType::COMPRESSION_PATAS), "COMPRESSION_PATAS" }, - { static_cast(CompressionType::COMPRESSION_ALP), "COMPRESSION_ALP" }, - { static_cast(CompressionType::COMPRESSION_ALPRD), "COMPRESSION_ALPRD" }, - { static_cast(CompressionType::COMPRESSION_ZSTD), "COMPRESSION_ZSTD" }, - { static_cast(CompressionType::COMPRESSION_ROARING), "COMPRESSION_ROARING" }, - { static_cast(CompressionType::COMPRESSION_EMPTY), "COMPRESSION_EMPTY" }, - { static_cast(CompressionType::COMPRESSION_DICT_FSST), "COMPRESSION_DICT_FSST" }, + { static_cast(CompressionType::COMPRESSION_AUTO), "AUTO" }, + { static_cast(CompressionType::COMPRESSION_UNCOMPRESSED), "UNCOMPRESSED" }, + { static_cast(CompressionType::COMPRESSION_CONSTANT), "CONSTANT" }, + { static_cast(CompressionType::COMPRESSION_RLE), "RLE" }, + { static_cast(CompressionType::COMPRESSION_DICTIONARY), "DICTIONARY" }, + { static_cast(CompressionType::COMPRESSION_PFOR_DELTA), "PFOR" }, + { static_cast(CompressionType::COMPRESSION_BITPACKING), "BITPACKING" }, + { static_cast(CompressionType::COMPRESSION_FSST), "FSST" }, + { static_cast(CompressionType::COMPRESSION_CHIMP), "CHIMP" }, + { static_cast(CompressionType::COMPRESSION_PATAS), "PATAS" }, + { static_cast(CompressionType::COMPRESSION_ALP), "ALP" }, + { static_cast(CompressionType::COMPRESSION_ALPRD), "ALPRD" }, + { static_cast(CompressionType::COMPRESSION_ZSTD), "ZSTD" }, + { static_cast(CompressionType::COMPRESSION_ROARING), "ROARING" }, + { static_cast(CompressionType::COMPRESSION_EMPTY), "EMPTY" }, + { static_cast(CompressionType::COMPRESSION_DICT_FSST), "DICT_FSST" }, { static_cast(CompressionType::COMPRESSION_COUNT), "COMPRESSION_COUNT" } }; return values; @@ -1216,9 +1263,9 @@ const StringUtil::EnumStringLiteral *GetCoordinateReferenceSystemTypeValues() { static constexpr StringUtil::EnumStringLiteral values[] { { static_cast(CoordinateReferenceSystemType::INVALID), "INVALID" }, { static_cast(CoordinateReferenceSystemType::SRID), "SRID" }, + { static_cast(CoordinateReferenceSystemType::AUTH_CODE), "AUTH_CODE" }, { static_cast(CoordinateReferenceSystemType::PROJJSON), "PROJJSON" }, - { static_cast(CoordinateReferenceSystemType::WKT2_2019), "WKT2_2019" }, - { static_cast(CoordinateReferenceSystemType::AUTH_CODE), "AUTH_CODE" } + { static_cast(CoordinateReferenceSystemType::WKT2_2019), "WKT2_2019" } }; return values; } @@ -1491,6 +1538,24 @@ DeprecatedIndexType EnumUtil::FromString(const char *value) return static_cast(StringUtil::StringToEnum(GetDeprecatedIndexTypeValues(), 3, "DeprecatedIndexType", value)); } +const StringUtil::EnumStringLiteral *GetDeprecatedUsingKeySyntaxValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(DeprecatedUsingKeySyntax::DEFAULT), "DEFAULT" }, + { static_cast(DeprecatedUsingKeySyntax::UNION_AS_UNION_ALL), "UNION_AS_UNION_ALL" } + }; + return values; +} + +template<> +const char* EnumUtil::ToChars(DeprecatedUsingKeySyntax value) { + return StringUtil::EnumToString(GetDeprecatedUsingKeySyntaxValues(), 2, "DeprecatedUsingKeySyntax", static_cast(value)); +} + +template<> +DeprecatedUsingKeySyntax EnumUtil::FromString(const char *value) { + return static_cast(StringUtil::StringToEnum(GetDeprecatedUsingKeySyntaxValues(), 2, "DeprecatedUsingKeySyntax", value)); +} + const StringUtil::EnumStringLiteral *GetDestroyBufferUponValues() { static constexpr StringUtil::EnumStringLiteral values[] { { static_cast(DestroyBufferUpon::BLOCK), "BLOCK" }, @@ -1728,6 +1793,7 @@ const StringUtil::EnumStringLiteral *GetExpressionClassValues() { { static_cast(ExpressionClass::POSITIONAL_REFERENCE), "POSITIONAL_REFERENCE" }, { static_cast(ExpressionClass::BETWEEN), "BETWEEN" }, { static_cast(ExpressionClass::LAMBDA_REF), "LAMBDA_REF" }, + { static_cast(ExpressionClass::TYPE), "TYPE" }, { static_cast(ExpressionClass::BOUND_AGGREGATE), "BOUND_AGGREGATE" }, { static_cast(ExpressionClass::BOUND_CASE), "BOUND_CASE" }, { static_cast(ExpressionClass::BOUND_CAST), "BOUND_CAST" }, @@ -1754,12 +1820,12 @@ const StringUtil::EnumStringLiteral *GetExpressionClassValues() { template<> const char* EnumUtil::ToChars(ExpressionClass value) { - return StringUtil::EnumToString(GetExpressionClassValues(), 40, "ExpressionClass", static_cast(value)); + return StringUtil::EnumToString(GetExpressionClassValues(), 41, "ExpressionClass", static_cast(value)); } template<> ExpressionClass EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExpressionClassValues(), 40, "ExpressionClass", value)); + return static_cast(StringUtil::StringToEnum(GetExpressionClassValues(), 41, "ExpressionClass", value)); } const StringUtil::EnumStringLiteral *GetExpressionTypeValues() { @@ -1827,6 +1893,7 @@ const StringUtil::EnumStringLiteral *GetExpressionTypeValues() { { static_cast(ExpressionType::FUNCTION_REF), "FUNCTION_REF" }, { static_cast(ExpressionType::TABLE_REF), "TABLE_REF" }, { static_cast(ExpressionType::LAMBDA_REF), "LAMBDA_REF" }, + { static_cast(ExpressionType::TYPE), "TYPE" }, { static_cast(ExpressionType::CAST), "CAST" }, { static_cast(ExpressionType::BOUND_REF), "BOUND_REF" }, { static_cast(ExpressionType::BOUND_COLUMN_REF), "BOUND_COLUMN_REF" }, @@ -1842,12 +1909,12 @@ const StringUtil::EnumStringLiteral *GetExpressionTypeValues() { template<> const char* EnumUtil::ToChars(ExpressionType value) { - return StringUtil::EnumToString(GetExpressionTypeValues(), 72, "ExpressionType", static_cast(value)); + return StringUtil::EnumToString(GetExpressionTypeValues(), 73, "ExpressionType", static_cast(value)); } template<> ExpressionType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExpressionTypeValues(), 72, "ExpressionType", value)); + return static_cast(StringUtil::StringToEnum(GetExpressionTypeValues(), 73, "ExpressionType", value)); } const StringUtil::EnumStringLiteral *GetExtensionABITypeValues() { @@ -1952,6 +2019,25 @@ ExtraDropInfoType EnumUtil::FromString(const char *value) { return static_cast(StringUtil::StringToEnum(GetExtraDropInfoTypeValues(), 2, "ExtraDropInfoType", value)); } +const StringUtil::EnumStringLiteral *GetExtraPersistentColumnDataTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExtraPersistentColumnDataType::INVALID), "INVALID" }, + { static_cast(ExtraPersistentColumnDataType::VARIANT), "VARIANT" }, + { static_cast(ExtraPersistentColumnDataType::GEOMETRY), "GEOMETRY" } + }; + return values; +} + +template<> +const char* EnumUtil::ToChars(ExtraPersistentColumnDataType value) { + return StringUtil::EnumToString(GetExtraPersistentColumnDataTypeValues(), 3, "ExtraPersistentColumnDataType", static_cast(value)); +} + +template<> +ExtraPersistentColumnDataType EnumUtil::FromString(const char *value) { + return static_cast(StringUtil::StringToEnum(GetExtraPersistentColumnDataTypeValues(), 3, "ExtraPersistentColumnDataType", value)); +} + const StringUtil::EnumStringLiteral *GetExtraTypeInfoTypeValues() { static constexpr StringUtil::EnumStringLiteral values[] { { static_cast(ExtraTypeInfoType::INVALID_TYPE_INFO), "INVALID_TYPE_INFO" }, @@ -1961,7 +2047,7 @@ const StringUtil::EnumStringLiteral *GetExtraTypeInfoTypeValues() { { static_cast(ExtraTypeInfoType::LIST_TYPE_INFO), "LIST_TYPE_INFO" }, { static_cast(ExtraTypeInfoType::STRUCT_TYPE_INFO), "STRUCT_TYPE_INFO" }, { static_cast(ExtraTypeInfoType::ENUM_TYPE_INFO), "ENUM_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::USER_TYPE_INFO), "USER_TYPE_INFO" }, + { static_cast(ExtraTypeInfoType::UNBOUND_TYPE_INFO), "UNBOUND_TYPE_INFO" }, { static_cast(ExtraTypeInfoType::AGGREGATE_STATE_TYPE_INFO), "AGGREGATE_STATE_TYPE_INFO" }, { static_cast(ExtraTypeInfoType::ARRAY_TYPE_INFO), "ARRAY_TYPE_INFO" }, { static_cast(ExtraTypeInfoType::ANY_TYPE_INFO), "ANY_TYPE_INFO" }, @@ -2759,8 +2845,9 @@ const StringUtil::EnumStringLiteral *GetLogicalTypeIdValues() { { static_cast(LogicalTypeId::SQLNULL), "NULL" }, { static_cast(LogicalTypeId::UNKNOWN), "UNKNOWN" }, { static_cast(LogicalTypeId::ANY), "ANY" }, - { static_cast(LogicalTypeId::USER), "USER" }, + { static_cast(LogicalTypeId::UNBOUND), "UNBOUND" }, { static_cast(LogicalTypeId::TEMPLATE), "TEMPLATE" }, + { static_cast(LogicalTypeId::TYPE), "TYPE" }, { static_cast(LogicalTypeId::BOOLEAN), "BOOLEAN" }, { static_cast(LogicalTypeId::TINYINT), "TINYINT" }, { static_cast(LogicalTypeId::SMALLINT), "SMALLINT" }, @@ -2812,12 +2899,12 @@ const StringUtil::EnumStringLiteral *GetLogicalTypeIdValues() { template<> const char* EnumUtil::ToChars(LogicalTypeId value) { - return StringUtil::EnumToString(GetLogicalTypeIdValues(), 51, "LogicalTypeId", static_cast(value)); + return StringUtil::EnumToString(GetLogicalTypeIdValues(), 52, "LogicalTypeId", static_cast(value)); } template<> LogicalTypeId EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetLogicalTypeIdValues(), 51, "LogicalTypeId", value)); + return static_cast(StringUtil::StringToEnum(GetLogicalTypeIdValues(), 52, "LogicalTypeId", value)); } const StringUtil::EnumStringLiteral *GetLookupResultTypeValues() { @@ -2895,19 +2982,21 @@ const StringUtil::EnumStringLiteral *GetMemoryTagValues() { { static_cast(MemoryTag::EXTENSION), "EXTENSION" }, { static_cast(MemoryTag::TRANSACTION), "TRANSACTION" }, { static_cast(MemoryTag::EXTERNAL_FILE_CACHE), "EXTERNAL_FILE_CACHE" }, - { static_cast(MemoryTag::WINDOW), "WINDOW" } + { static_cast(MemoryTag::WINDOW), "WINDOW" }, + { static_cast(MemoryTag::OBJECT_CACHE), "OBJECT_CACHE" }, + { static_cast(MemoryTag::UNKNOWN), "UNKNOWN" } }; return values; } template<> const char* EnumUtil::ToChars(MemoryTag value) { - return StringUtil::EnumToString(GetMemoryTagValues(), 15, "MemoryTag", static_cast(value)); + return StringUtil::EnumToString(GetMemoryTagValues(), 17, "MemoryTag", static_cast(value)); } template<> MemoryTag EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetMemoryTagValues(), 15, "MemoryTag", value)); + return static_cast(StringUtil::StringToEnum(GetMemoryTagValues(), 17, "MemoryTag", value)); } const StringUtil::EnumStringLiteral *GetMergeActionConditionValues() { @@ -3038,9 +3127,7 @@ const StringUtil::EnumStringLiteral *GetMetricTypeValues() { { static_cast(MetricType::OPTIMIZER_COLUMN_LIFETIME), "OPTIMIZER_COLUMN_LIFETIME" }, { static_cast(MetricType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE), "OPTIMIZER_BUILD_SIDE_PROBE_SIDE" }, { static_cast(MetricType::OPTIMIZER_LIMIT_PUSHDOWN), "OPTIMIZER_LIMIT_PUSHDOWN" }, - { static_cast(MetricType::OPTIMIZER_ROW_GROUP_PRUNER), "OPTIMIZER_ROW_GROUP_PRUNER" }, { static_cast(MetricType::OPTIMIZER_TOP_N), "OPTIMIZER_TOP_N" }, - { static_cast(MetricType::OPTIMIZER_TOP_N_WINDOW_ELIMINATION), "OPTIMIZER_TOP_N_WINDOW_ELIMINATION" }, { static_cast(MetricType::OPTIMIZER_COMPRESSED_MATERIALIZATION), "OPTIMIZER_COMPRESSED_MATERIALIZATION" }, { static_cast(MetricType::OPTIMIZER_DUPLICATE_GROUPS), "OPTIMIZER_DUPLICATE_GROUPS" }, { static_cast(MetricType::OPTIMIZER_REORDER_FILTER), "OPTIMIZER_REORDER_FILTER" }, @@ -3051,6 +3138,8 @@ const StringUtil::EnumStringLiteral *GetMetricTypeValues() { { static_cast(MetricType::OPTIMIZER_SUM_REWRITER), "OPTIMIZER_SUM_REWRITER" }, { static_cast(MetricType::OPTIMIZER_LATE_MATERIALIZATION), "OPTIMIZER_LATE_MATERIALIZATION" }, { static_cast(MetricType::OPTIMIZER_CTE_INLINING), "OPTIMIZER_CTE_INLINING" }, + { static_cast(MetricType::OPTIMIZER_ROW_GROUP_PRUNER), "OPTIMIZER_ROW_GROUP_PRUNER" }, + { static_cast(MetricType::OPTIMIZER_TOP_N_WINDOW_ELIMINATION), "OPTIMIZER_TOP_N_WINDOW_ELIMINATION" }, { static_cast(MetricType::OPTIMIZER_COMMON_SUBPLAN), "OPTIMIZER_COMMON_SUBPLAN" }, { static_cast(MetricType::OPTIMIZER_JOIN_ELIMINATION), "OPTIMIZER_JOIN_ELIMINATION" }, { static_cast(MetricType::OPTIMIZER_WINDOW_SELF_JOIN), "OPTIMIZER_WINDOW_SELF_JOIN" }, @@ -3315,9 +3404,7 @@ const StringUtil::EnumStringLiteral *GetOptimizerTypeValues() { { static_cast(OptimizerType::COLUMN_LIFETIME), "COLUMN_LIFETIME" }, { static_cast(OptimizerType::BUILD_SIDE_PROBE_SIDE), "BUILD_SIDE_PROBE_SIDE" }, { static_cast(OptimizerType::LIMIT_PUSHDOWN), "LIMIT_PUSHDOWN" }, - { static_cast(OptimizerType::ROW_GROUP_PRUNER), "ROW_GROUP_PRUNER" }, { static_cast(OptimizerType::TOP_N), "TOP_N" }, - { static_cast(OptimizerType::TOP_N_WINDOW_ELIMINATION), "TOP_N_WINDOW_ELIMINATION" }, { static_cast(OptimizerType::COMPRESSED_MATERIALIZATION), "COMPRESSED_MATERIALIZATION" }, { static_cast(OptimizerType::DUPLICATE_GROUPS), "DUPLICATE_GROUPS" }, { static_cast(OptimizerType::REORDER_FILTER), "REORDER_FILTER" }, @@ -3328,6 +3415,8 @@ const StringUtil::EnumStringLiteral *GetOptimizerTypeValues() { { static_cast(OptimizerType::SUM_REWRITER), "SUM_REWRITER" }, { static_cast(OptimizerType::LATE_MATERIALIZATION), "LATE_MATERIALIZATION" }, { static_cast(OptimizerType::CTE_INLINING), "CTE_INLINING" }, + { static_cast(OptimizerType::ROW_GROUP_PRUNER), "ROW_GROUP_PRUNER" }, + { static_cast(OptimizerType::TOP_N_WINDOW_ELIMINATION), "TOP_N_WINDOW_ELIMINATION" }, { static_cast(OptimizerType::COMMON_SUBPLAN), "COMMON_SUBPLAN" }, { static_cast(OptimizerType::JOIN_ELIMINATION), "JOIN_ELIMINATION" }, { static_cast(OptimizerType::WINDOW_SELF_JOIN), "WINDOW_SELF_JOIN" } @@ -3345,6 +3434,24 @@ OptimizerType EnumUtil::FromString(const char *value) { return static_cast(StringUtil::StringToEnum(GetOptimizerTypeValues(), 34, "OptimizerType", value)); } +const StringUtil::EnumStringLiteral *GetOrderByColumnTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OrderByColumnType::NUMERIC), "NUMERIC" }, + { static_cast(OrderByColumnType::STRING), "STRING" } + }; + return values; +} + +template<> +const char* EnumUtil::ToChars(OrderByColumnType value) { + return StringUtil::EnumToString(GetOrderByColumnTypeValues(), 2, "OrderByColumnType", static_cast(value)); +} + +template<> +OrderByColumnType EnumUtil::FromString(const char *value) { + return static_cast(StringUtil::StringToEnum(GetOrderByColumnTypeValues(), 2, "OrderByColumnType", value)); +} + const StringUtil::EnumStringLiteral *GetOrderByNullTypeValues() { static constexpr StringUtil::EnumStringLiteral values[] { { static_cast(OrderByNullType::INVALID), "INVALID" }, @@ -3368,6 +3475,24 @@ OrderByNullType EnumUtil::FromString(const char *value) { return static_cast(StringUtil::StringToEnum(GetOrderByNullTypeValues(), 7, "OrderByNullType", value)); } +const StringUtil::EnumStringLiteral *GetOrderByStatisticsValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OrderByStatistics::MIN), "MIN" }, + { static_cast(OrderByStatistics::MAX), "MAX" } + }; + return values; +} + +template<> +const char* EnumUtil::ToChars(OrderByStatistics value) { + return StringUtil::EnumToString(GetOrderByStatisticsValues(), 2, "OrderByStatistics", static_cast(value)); +} + +template<> +OrderByStatistics EnumUtil::FromString(const char *value) { + return static_cast(StringUtil::StringToEnum(GetOrderByStatisticsValues(), 2, "OrderByStatistics", value)); +} + const StringUtil::EnumStringLiteral *GetOrderPreservationTypeValues() { static constexpr StringUtil::EnumStringLiteral values[] { { static_cast(OrderPreservationType::NO_ORDER), "NO_ORDER" }, @@ -4326,19 +4451,20 @@ const StringUtil::EnumStringLiteral *GetShowTypeValues() { static constexpr StringUtil::EnumStringLiteral values[] { { static_cast(ShowType::SUMMARY), "SUMMARY" }, { static_cast(ShowType::DESCRIBE), "DESCRIBE" }, - { static_cast(ShowType::SHOW_FROM), "SHOW_FROM" } + { static_cast(ShowType::SHOW_FROM), "SHOW_FROM" }, + { static_cast(ShowType::SHOW_UNQUALIFIED), "SHOW_UNQUALIFIED" } }; return values; } template<> const char* EnumUtil::ToChars(ShowType value) { - return StringUtil::EnumToString(GetShowTypeValues(), 3, "ShowType", static_cast(value)); + return StringUtil::EnumToString(GetShowTypeValues(), 4, "ShowType", static_cast(value)); } template<> ShowType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetShowTypeValues(), 3, "ShowType", value)); + return static_cast(StringUtil::StringToEnum(GetShowTypeValues(), 4, "ShowType", value)); } const StringUtil::EnumStringLiteral *GetSimplifiedTokenTypeValues() { @@ -5113,6 +5239,7 @@ UnionInvalidReason EnumUtil::FromString(const char *value) { const StringUtil::EnumStringLiteral *GetVariantChildLookupModeValues() { static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(VariantChildLookupMode::INVALID), "INVALID" }, { static_cast(VariantChildLookupMode::BY_KEY), "BY_KEY" }, { static_cast(VariantChildLookupMode::BY_INDEX), "BY_INDEX" } }; @@ -5121,12 +5248,12 @@ const StringUtil::EnumStringLiteral *GetVariantChildLookupModeValues() { template<> const char* EnumUtil::ToChars(VariantChildLookupMode value) { - return StringUtil::EnumToString(GetVariantChildLookupModeValues(), 2, "VariantChildLookupMode", static_cast(value)); + return StringUtil::EnumToString(GetVariantChildLookupModeValues(), 3, "VariantChildLookupMode", static_cast(value)); } template<> VariantChildLookupMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetVariantChildLookupModeValues(), 2, "VariantChildLookupMode", value)); + return static_cast(StringUtil::StringToEnum(GetVariantChildLookupModeValues(), 3, "VariantChildLookupMode", value)); } const StringUtil::EnumStringLiteral *GetVariantLogicalTypeValues() { diff --git a/src/duckdb/src/common/enums/catalog_type.cpp b/src/duckdb/src/common/enums/catalog_type.cpp index 55dbcb41a..6993b2fa1 100644 --- a/src/duckdb/src/common/enums/catalog_type.cpp +++ b/src/duckdb/src/common/enums/catalog_type.cpp @@ -9,6 +9,8 @@ string CatalogTypeToString(CatalogType type) { switch (type) { case CatalogType::COLLATION_ENTRY: return "Collation"; + case CatalogType::COORDINATE_SYSTEM_ENTRY: + return "Coordinate System"; case CatalogType::TYPE_ENTRY: return "Type"; case CatalogType::TABLE_ENTRY: @@ -58,6 +60,9 @@ CatalogType CatalogTypeFromString(const string &type) { if (type == "Collation") { return CatalogType::COLLATION_ENTRY; } + if (type == "Coordinate System") { + return CatalogType::COORDINATE_SYSTEM_ENTRY; + } if (type == "Type") { return CatalogType::TYPE_ENTRY; } diff --git a/src/duckdb/src/common/enums/compression_type.cpp b/src/duckdb/src/common/enums/compression_type.cpp index 427cfbe91..15cfdac70 100644 --- a/src/duckdb/src/common/enums/compression_type.cpp +++ b/src/duckdb/src/common/enums/compression_type.cpp @@ -73,41 +73,6 @@ CompressionAvailabilityResult CompressionTypeIsAvailable(CompressionType compres return CompressionAvailabilityResult(); } -CompressionType CompressionTypeFromString(const string &str) { - auto compression = StringUtil::Lower(str); - //! NOTE: this explicitly does not include 'constant' and 'empty validity', these are internal compression functions - //! not general purpose - if (compression == "uncompressed") { - return CompressionType::COMPRESSION_UNCOMPRESSED; - } else if (compression == "rle") { - return CompressionType::COMPRESSION_RLE; - } else if (compression == "dictionary") { - return CompressionType::COMPRESSION_DICTIONARY; - } else if (compression == "pfor") { - return CompressionType::COMPRESSION_PFOR_DELTA; - } else if (compression == "bitpacking") { - return CompressionType::COMPRESSION_BITPACKING; - } else if (compression == "fsst") { - return CompressionType::COMPRESSION_FSST; - } else if (compression == "chimp") { - return CompressionType::COMPRESSION_CHIMP; - } else if (compression == "patas") { - return CompressionType::COMPRESSION_PATAS; - } else if (compression == "zstd") { - return CompressionType::COMPRESSION_ZSTD; - } else if (compression == "alp") { - return CompressionType::COMPRESSION_ALP; - } else if (compression == "alprd") { - return CompressionType::COMPRESSION_ALPRD; - } else if (compression == "roaring") { - return CompressionType::COMPRESSION_ROARING; - } else if (compression == "dict_fsst") { - return CompressionType::COMPRESSION_DICT_FSST; - } else { - return CompressionType::COMPRESSION_AUTO; - } -} - string CompressionTypeToString(CompressionType type) { switch (type) { case CompressionType::COMPRESSION_AUTO: diff --git a/src/duckdb/src/common/enums/expression_type.cpp b/src/duckdb/src/common/enums/expression_type.cpp index f1375d3a1..42014a9d1 100644 --- a/src/duckdb/src/common/enums/expression_type.cpp +++ b/src/duckdb/src/common/enums/expression_type.cpp @@ -147,6 +147,8 @@ string ExpressionTypeToString(ExpressionType type) { return "LAMBDA"; case ExpressionType::ARROW: return "ARROW"; + case ExpressionType::TYPE: + return "TYPE"; case ExpressionType::BOUND_EXPANDED: return "BOUND_EXPANDED"; case ExpressionType::INVALID: @@ -196,6 +198,8 @@ string ExpressionClassToString(ExpressionClass type) { return "POSITIONAL_REFERENCE"; case ExpressionClass::BETWEEN: return "BETWEEN"; + case ExpressionClass::TYPE: + return "TYPE"; case ExpressionClass::BOUND_AGGREGATE: return "BOUND_AGGREGATE"; case ExpressionClass::BOUND_CASE: diff --git a/src/duckdb/src/common/enums/metric_type.cpp b/src/duckdb/src/common/enums/metric_type.cpp index f7788ef9c..acfac3b5d 100644 --- a/src/duckdb/src/common/enums/metric_type.cpp +++ b/src/duckdb/src/common/enums/metric_type.cpp @@ -7,11 +7,75 @@ namespace duckdb { profiler_settings_t MetricsUtils::GetAllMetrics() { - profiler_settings_t result; - for (auto metric = START_CORE; metric <= END_PHASE_TIMING; metric++) { - result.insert(static_cast(metric)); - } - return result; + return { + MetricType::ALL_OPTIMIZERS, + MetricType::ATTACH_LOAD_STORAGE_LATENCY, + MetricType::ATTACH_REPLAY_WAL_LATENCY, + MetricType::BLOCKED_THREAD_TIME, + MetricType::CHECKPOINT_LATENCY, + MetricType::COMMIT_LOCAL_STORAGE_LATENCY, + MetricType::CPU_TIME, + MetricType::CUMULATIVE_CARDINALITY, + MetricType::CUMULATIVE_OPTIMIZER_TIMING, + MetricType::CUMULATIVE_ROWS_SCANNED, + MetricType::EXTRA_INFO, + MetricType::LATENCY, + MetricType::OPERATOR_CARDINALITY, + MetricType::OPERATOR_NAME, + MetricType::OPERATOR_ROWS_SCANNED, + MetricType::OPERATOR_TIMING, + MetricType::OPERATOR_TYPE, + MetricType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE, + MetricType::OPTIMIZER_COLUMN_LIFETIME, + MetricType::OPTIMIZER_COMMON_AGGREGATE, + MetricType::OPTIMIZER_COMMON_SUBEXPRESSIONS, + MetricType::OPTIMIZER_COMMON_SUBPLAN, + MetricType::OPTIMIZER_COMPRESSED_MATERIALIZATION, + MetricType::OPTIMIZER_CTE_FILTER_PUSHER, + MetricType::OPTIMIZER_CTE_INLINING, + MetricType::OPTIMIZER_DELIMINATOR, + MetricType::OPTIMIZER_DUPLICATE_GROUPS, + MetricType::OPTIMIZER_EMPTY_RESULT_PULLUP, + MetricType::OPTIMIZER_EXPRESSION_REWRITER, + MetricType::OPTIMIZER_EXTENSION, + MetricType::OPTIMIZER_FILTER_PULLUP, + MetricType::OPTIMIZER_FILTER_PUSHDOWN, + MetricType::OPTIMIZER_IN_CLAUSE, + MetricType::OPTIMIZER_JOIN_ELIMINATION, + MetricType::OPTIMIZER_JOIN_FILTER_PUSHDOWN, + MetricType::OPTIMIZER_JOIN_ORDER, + MetricType::OPTIMIZER_LATE_MATERIALIZATION, + MetricType::OPTIMIZER_LIMIT_PUSHDOWN, + MetricType::OPTIMIZER_MATERIALIZED_CTE, + MetricType::OPTIMIZER_REGEX_RANGE, + MetricType::OPTIMIZER_REORDER_FILTER, + MetricType::OPTIMIZER_ROW_GROUP_PRUNER, + MetricType::OPTIMIZER_SAMPLING_PUSHDOWN, + MetricType::OPTIMIZER_STATISTICS_PROPAGATION, + MetricType::OPTIMIZER_SUM_REWRITER, + MetricType::OPTIMIZER_TOP_N, + MetricType::OPTIMIZER_TOP_N_WINDOW_ELIMINATION, + MetricType::OPTIMIZER_UNNEST_REWRITER, + MetricType::OPTIMIZER_UNUSED_COLUMNS, + MetricType::OPTIMIZER_WINDOW_SELF_JOIN, + MetricType::PHYSICAL_PLANNER, + MetricType::PHYSICAL_PLANNER_COLUMN_BINDING, + MetricType::PHYSICAL_PLANNER_CREATE_PLAN, + MetricType::PHYSICAL_PLANNER_RESOLVE_TYPES, + MetricType::PLANNER, + MetricType::PLANNER_BINDING, + MetricType::QUERY_NAME, + MetricType::RESULT_SET_SIZE, + MetricType::ROWS_RETURNED, + MetricType::SYSTEM_PEAK_BUFFER_MEMORY, + MetricType::SYSTEM_PEAK_TEMP_DIR_SIZE, + MetricType::TOTAL_BYTES_READ, + MetricType::TOTAL_BYTES_WRITTEN, + MetricType::TOTAL_MEMORY_ALLOCATED, + MetricType::WAITING_TO_ATTACH_LATENCY, + MetricType::WAL_REPLAY_ENTRY_COUNT, + MetricType::WRITE_TO_WAL_LATENCY, + }; } profiler_settings_t MetricsUtils::GetMetricsByGroupType(MetricGroup type) { @@ -38,15 +102,32 @@ profiler_settings_t MetricsUtils::GetMetricsByGroupType(MetricGroup type) { } profiler_settings_t MetricsUtils::GetCoreMetrics() { - profiler_settings_t result; - for (auto metric = START_CORE; metric <= END_CORE; metric++) { - result.insert(static_cast(metric)); - } - return result; + return { + MetricType::CPU_TIME, + MetricType::CUMULATIVE_CARDINALITY, + MetricType::CUMULATIVE_ROWS_SCANNED, + MetricType::EXTRA_INFO, + MetricType::LATENCY, + MetricType::QUERY_NAME, + MetricType::RESULT_SET_SIZE, + MetricType::ROWS_RETURNED, + }; } bool MetricsUtils::IsCoreMetric(MetricType type) { - return static_cast(type) <= END_CORE; + switch(type) { + case MetricType::CPU_TIME: + case MetricType::CUMULATIVE_CARDINALITY: + case MetricType::CUMULATIVE_ROWS_SCANNED: + case MetricType::EXTRA_INFO: + case MetricType::LATENCY: + case MetricType::QUERY_NAME: + case MetricType::RESULT_SET_SIZE: + case MetricType::ROWS_RETURNED: + return true; + default: + return false; + } } profiler_settings_t MetricsUtils::GetDefaultMetrics() { @@ -115,39 +196,78 @@ bool MetricsUtils::IsDefaultMetric(MetricType type) { } profiler_settings_t MetricsUtils::GetExecutionMetrics() { - profiler_settings_t result; - for (auto metric = START_EXECUTION; metric <= END_EXECUTION; metric++) { - result.insert(static_cast(metric)); - } - return result; + return { + MetricType::BLOCKED_THREAD_TIME, + MetricType::SYSTEM_PEAK_BUFFER_MEMORY, + MetricType::SYSTEM_PEAK_TEMP_DIR_SIZE, + MetricType::TOTAL_MEMORY_ALLOCATED, + }; } bool MetricsUtils::IsExecutionMetric(MetricType type) { - return static_cast(type) >= START_EXECUTION && static_cast(type) <= END_EXECUTION; + switch(type) { + case MetricType::BLOCKED_THREAD_TIME: + case MetricType::SYSTEM_PEAK_BUFFER_MEMORY: + case MetricType::SYSTEM_PEAK_TEMP_DIR_SIZE: + case MetricType::TOTAL_MEMORY_ALLOCATED: + return true; + default: + return false; + } } profiler_settings_t MetricsUtils::GetFileMetrics() { - profiler_settings_t result; - for (auto metric = START_FILE; metric <= END_FILE; metric++) { - result.insert(static_cast(metric)); - } - return result; + return { + MetricType::ATTACH_LOAD_STORAGE_LATENCY, + MetricType::ATTACH_REPLAY_WAL_LATENCY, + MetricType::CHECKPOINT_LATENCY, + MetricType::COMMIT_LOCAL_STORAGE_LATENCY, + MetricType::TOTAL_BYTES_READ, + MetricType::TOTAL_BYTES_WRITTEN, + MetricType::WAITING_TO_ATTACH_LATENCY, + MetricType::WAL_REPLAY_ENTRY_COUNT, + MetricType::WRITE_TO_WAL_LATENCY, + }; } bool MetricsUtils::IsFileMetric(MetricType type) { - return static_cast(type) >= START_FILE && static_cast(type) <= END_FILE; + switch(type) { + case MetricType::ATTACH_LOAD_STORAGE_LATENCY: + case MetricType::ATTACH_REPLAY_WAL_LATENCY: + case MetricType::CHECKPOINT_LATENCY: + case MetricType::COMMIT_LOCAL_STORAGE_LATENCY: + case MetricType::TOTAL_BYTES_READ: + case MetricType::TOTAL_BYTES_WRITTEN: + case MetricType::WAITING_TO_ATTACH_LATENCY: + case MetricType::WAL_REPLAY_ENTRY_COUNT: + case MetricType::WRITE_TO_WAL_LATENCY: + return true; + default: + return false; + } } profiler_settings_t MetricsUtils::GetOperatorMetrics() { - profiler_settings_t result; - for (auto metric = START_OPERATOR; metric <= END_OPERATOR; metric++) { - result.insert(static_cast(metric)); - } - return result; + return { + MetricType::OPERATOR_CARDINALITY, + MetricType::OPERATOR_NAME, + MetricType::OPERATOR_ROWS_SCANNED, + MetricType::OPERATOR_TIMING, + MetricType::OPERATOR_TYPE, + }; } bool MetricsUtils::IsOperatorMetric(MetricType type) { - return static_cast(type) >= START_OPERATOR && static_cast(type) <= END_OPERATOR; + switch(type) { + case MetricType::OPERATOR_CARDINALITY: + case MetricType::OPERATOR_NAME: + case MetricType::OPERATOR_ROWS_SCANNED: + case MetricType::OPERATOR_TIMING: + case MetricType::OPERATOR_TYPE: + return true; + default: + return false; + } } profiler_settings_t MetricsUtils::GetOptimizerMetrics() { @@ -190,15 +310,32 @@ OptimizerType MetricsUtils::GetOptimizerTypeByMetric(MetricType type) { } profiler_settings_t MetricsUtils::GetPhaseTimingMetrics() { - profiler_settings_t result; - for (auto metric = START_PHASE_TIMING; metric <= END_PHASE_TIMING; metric++) { - result.insert(static_cast(metric)); - } - return result; + return { + MetricType::ALL_OPTIMIZERS, + MetricType::CUMULATIVE_OPTIMIZER_TIMING, + MetricType::PHYSICAL_PLANNER, + MetricType::PHYSICAL_PLANNER_COLUMN_BINDING, + MetricType::PHYSICAL_PLANNER_CREATE_PLAN, + MetricType::PHYSICAL_PLANNER_RESOLVE_TYPES, + MetricType::PLANNER, + MetricType::PLANNER_BINDING, + }; } bool MetricsUtils::IsPhaseTimingMetric(MetricType type) { - return static_cast(type) >= START_PHASE_TIMING && static_cast(type) <= END_PHASE_TIMING; + switch(type) { + case MetricType::ALL_OPTIMIZERS: + case MetricType::CUMULATIVE_OPTIMIZER_TIMING: + case MetricType::PHYSICAL_PLANNER: + case MetricType::PHYSICAL_PLANNER_COLUMN_BINDING: + case MetricType::PHYSICAL_PLANNER_CREATE_PLAN: + case MetricType::PHYSICAL_PLANNER_RESOLVE_TYPES: + case MetricType::PLANNER: + case MetricType::PLANNER_BINDING: + return true; + default: + return false; + } } profiler_settings_t MetricsUtils::GetRootScopeMetrics() { diff --git a/src/duckdb/src/common/error_data.cpp b/src/duckdb/src/common/error_data.cpp index 8b8da300d..638f6608f 100644 --- a/src/duckdb/src/common/error_data.cpp +++ b/src/duckdb/src/common/error_data.cpp @@ -18,35 +18,40 @@ ErrorData::ErrorData(const std::exception &ex) : ErrorData(ex.what()) { } ErrorData::ErrorData(ExceptionType type, const string &message) - : initialized(true), type(type), raw_message(SanitizeErrorMessage(message)), - final_message(ConstructFinalMessage()) { + : initialized(true), type(type), raw_message(SanitizeErrorMessage(message)) { + // In the case of ExceptionType::INTERNAL, the stack trace is part of the final message. + // To construct it, we need to access extra_info, which has to be initialized first. + // Thus, we only set final_message in the constructor's body. + final_message = ConstructFinalMessage(); } ErrorData::ErrorData(const string &message) : initialized(true), type(ExceptionType::INVALID), raw_message(string()), final_message(string()) { // parse the constructed JSON if (message.empty() || message[0] != '{') { - // not JSON! Use the message as a raw Exception message and leave type as uninitialized - + // Not a JSON-formatted message. + // Use the message as a raw Exception message and leave the type as uninitialized. if (message == std::bad_alloc().what()) { type = ExceptionType::OUT_OF_MEMORY; raw_message = "Allocation failure"; } else { raw_message = message; } - } else { - auto info = StringUtil::ParseJSONMap(message)->Flatten(); - for (auto &entry : info) { - if (entry.first == "exception_type") { - type = Exception::StringToExceptionType(entry.second); - } else if (entry.first == "exception_message") { - raw_message = SanitizeErrorMessage(entry.second); - } else { - extra_info[entry.first] = entry.second; - } - } + final_message = ConstructFinalMessage(); + return; } + // JSON-formatted message. + auto info = StringUtil::ParseJSONMap(message)->Flatten(); + for (auto &entry : info) { + if (entry.first == "exception_type") { + type = Exception::StringToExceptionType(entry.second); + } else if (entry.first == "exception_message") { + raw_message = SanitizeErrorMessage(entry.second); + } else { + extra_info[entry.first] = entry.second; + } + } final_message = ConstructFinalMessage(); } @@ -60,7 +65,7 @@ string ErrorData::ConstructFinalMessage() const { error = Exception::ExceptionTypeToString(type) + " "; } error += "Error: " + raw_message; - if (type == ExceptionType::INTERNAL || type == ExceptionType::FATAL) { + if (type == ExceptionType::INTERNAL) { error += "\nThis error signals an assertion failure within DuckDB. This usually occurs due to " "unexpected conditions or errors in the program's logic.\nFor more information, see " "https://duckdb.org/docs/stable/dev/internal_errors"; @@ -97,6 +102,10 @@ void ErrorData::Merge(const ErrorData &other) { *this = other; return; } + if (Exception::InvalidatesDatabase(other.Type()) || other.type == ExceptionType::INTERNAL) { + // inherit severe types + type = other.type; + } final_message += "\n\n" + other.Message(); } diff --git a/src/duckdb/src/common/exception.cpp b/src/duckdb/src/common/exception.cpp index ce22091c8..3605a78c0 100644 --- a/src/duckdb/src/common/exception.cpp +++ b/src/duckdb/src/common/exception.cpp @@ -33,7 +33,7 @@ string Exception::ToJSON(ExceptionType type, const string &message) { string Exception::ToJSON(const unordered_map &extra_info, ExceptionType type, const string &message) { #ifndef DUCKDB_DEBUG_STACKTRACE // by default we only enable stack traces for internal exceptions - if (type == ExceptionType::INTERNAL || type == ExceptionType::FATAL) + if (type == ExceptionType::INTERNAL) #endif { auto extended_extra_info = extra_info; @@ -330,7 +330,7 @@ SerializationException::SerializationException(const string &msg) : Exception(Ex SequenceException::SequenceException(const string &msg) : Exception(ExceptionType::SEQUENCE, msg) { } -InterruptException::InterruptException() : Exception(ExceptionType::INTERRUPT, "Interrupted!") { +InterruptException::InterruptException() : Exception(ExceptionType::INTERRUPT, INTERRUPT_MESSAGE) { } FatalException::FatalException(ExceptionType type, const string &msg) : Exception(type, msg) { diff --git a/src/duckdb/src/common/extra_type_info.cpp b/src/duckdb/src/common/extra_type_info.cpp index 932c08c0c..dc34d88ec 100644 --- a/src/duckdb/src/common/extra_type_info.cpp +++ b/src/duckdb/src/common/extra_type_info.cpp @@ -6,6 +6,8 @@ #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" #include "duckdb/common/string_map_set.hpp" +#include "duckdb/parser/expression/constant_expression.hpp" +#include "duckdb/parser/expression/type_expression.hpp" namespace duckdb { @@ -261,30 +263,66 @@ shared_ptr AggregateStateTypeInfo::Copy() const { //===--------------------------------------------------------------------===// // User Type Info //===--------------------------------------------------------------------===// -UserTypeInfo::UserTypeInfo() : ExtraTypeInfo(ExtraTypeInfoType::USER_TYPE_INFO) { -} +void UnboundTypeInfo::Serialize(Serializer &serializer) const { + ExtraTypeInfo::Serialize(serializer); -UserTypeInfo::UserTypeInfo(string name_p) - : ExtraTypeInfo(ExtraTypeInfoType::USER_TYPE_INFO), user_type_name(std::move(name_p)) { -} + if (serializer.ShouldSerialize(7)) { + serializer.WritePropertyWithDefault>(204, "expr", expr); + return; + } -UserTypeInfo::UserTypeInfo(string name_p, vector modifiers_p) - : ExtraTypeInfo(ExtraTypeInfoType::USER_TYPE_INFO), user_type_name(std::move(name_p)), - user_type_modifiers(std::move(modifiers_p)) { -} + // Try to write this as an old "USER" type, if possible + if (expr->type != ExpressionType::TYPE) { + throw SerializationException( + "Cannot serialize non-type type expression when targeting database storage version '%s'", + serializer.GetOptions().serialization_compatibility.duckdb_version); + } -UserTypeInfo::UserTypeInfo(string catalog_p, string schema_p, string name_p, vector modifiers_p) - : ExtraTypeInfo(ExtraTypeInfoType::USER_TYPE_INFO), catalog(std::move(catalog_p)), schema(std::move(schema_p)), - user_type_name(std::move(name_p)), user_type_modifiers(std::move(modifiers_p)) { -} + auto &type_expr = expr->Cast(); + serializer.WritePropertyWithDefault(200, "name", type_expr.GetTypeName()); + serializer.WritePropertyWithDefault(201, "catalog", type_expr.GetCatalog()); + serializer.WritePropertyWithDefault(202, "schema", type_expr.GetSchema()); + + // Try to write the user type mods too + vector user_type_mods; + for (auto ¶m : type_expr.GetChildren()) { + if (param->type != ExpressionType::VALUE_CONSTANT) { + throw SerializationException( + "Cannot serialize non-constant type parameter when targeting serialization version %s", + serializer.GetOptions().serialization_compatibility.duckdb_version); + } -bool UserTypeInfo::EqualsInternal(ExtraTypeInfo *other_p) const { - auto &other = other_p->Cast(); - return other.user_type_name == user_type_name; + auto &const_expr = param->Cast(); + user_type_mods.push_back(const_expr.value); + } + + serializer.WritePropertyWithDefault>(203, "user_type_modifiers", user_type_mods); } -shared_ptr UserTypeInfo::Copy() const { - return make_shared_ptr(*this); +shared_ptr UnboundTypeInfo::Deserialize(Deserializer &deserializer) { + auto result = duckdb::shared_ptr(new UnboundTypeInfo()); + + deserializer.ReadPropertyWithDefault>(204, "expr", result->expr); + + if (!result->expr) { + // This is a legacy "USER" type + string name; + deserializer.ReadPropertyWithDefault(200, "name", name); + string catalog; + deserializer.ReadPropertyWithDefault(201, "catalog", catalog); + string schema; + deserializer.ReadPropertyWithDefault(202, "schema", schema); + + vector> user_type_mods; + auto mods = deserializer.ReadPropertyWithDefault>(203, "user_type_modifiers"); + for (auto &mod : mods) { + user_type_mods.push_back(make_uniq_base(mod)); + } + + result->expr = make_uniq(catalog, schema, name, std::move(user_type_mods)); + } + + return std::move(result); } //===--------------------------------------------------------------------===// @@ -523,4 +561,26 @@ shared_ptr GeoTypeInfo::Copy() const { return make_shared_ptr(*this); } +//===--------------------------------------------------------------------===// +// Unbound Type Info +//===--------------------------------------------------------------------===// +UnboundTypeInfo::UnboundTypeInfo() : ExtraTypeInfo(ExtraTypeInfoType::UNBOUND_TYPE_INFO) { +} + +UnboundTypeInfo::UnboundTypeInfo(unique_ptr expr_p) + : ExtraTypeInfo(ExtraTypeInfoType::UNBOUND_TYPE_INFO), expr(std::move(expr_p)) { +} + +bool UnboundTypeInfo::EqualsInternal(ExtraTypeInfo *other_p) const { + auto &other = other_p->Cast(); + if (!expr->Equals(*other.expr)) { + return false; + } + return true; +} + +shared_ptr UnboundTypeInfo::Copy() const { + return make_shared_ptr(expr->Copy()); +} + } // namespace duckdb diff --git a/src/duckdb/src/common/file_buffer.cpp b/src/duckdb/src/common/file_buffer.cpp index 94223eed3..babda0c6e 100644 --- a/src/duckdb/src/common/file_buffer.cpp +++ b/src/duckdb/src/common/file_buffer.cpp @@ -95,8 +95,8 @@ void FileBuffer::ResizeInternal(uint64_t new_size, uint64_t block_header_size) { } } -void FileBuffer::Resize(uint64_t new_size, BlockManager &block_manager) { - ResizeInternal(new_size, block_manager.GetBlockHeaderSize()); +void FileBuffer::Resize(uint64_t new_size, idx_t block_header_size) { + ResizeInternal(new_size, block_header_size); } void FileBuffer::Resize(BlockManager &block_manager) { diff --git a/src/duckdb/src/common/file_system.cpp b/src/duckdb/src/common/file_system.cpp index ce4f9022a..0705f6175 100644 --- a/src/duckdb/src/common/file_system.cpp +++ b/src/duckdb/src/common/file_system.cpp @@ -5,6 +5,7 @@ #include "duckdb/common/file_opener.hpp" #include "duckdb/common/helper.hpp" #include "duckdb/common/string_util.hpp" +#include "duckdb/common/multi_file/multi_file_list.hpp" #include "duckdb/common/windows.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/logging/log_type.hpp" @@ -60,6 +61,7 @@ constexpr FileOpenFlags FileFlags::FILE_FLAGS_EXCLUSIVE_CREATE; constexpr FileOpenFlags FileFlags::FILE_FLAGS_NULL_IF_EXISTS; constexpr FileOpenFlags FileFlags::FILE_FLAGS_MULTI_CLIENT_ACCESS; constexpr FileOpenFlags FileFlags::FILE_FLAGS_DISABLE_LOGGING; +constexpr FileOpenFlags FileFlags::FILE_FLAGS_ENABLE_EXTENSION_INSTALL; void FileOpenFlags::Verify() { #ifdef DEBUG @@ -172,11 +174,6 @@ string FileSystem::GetWorkingDirectory() { return string(buffer.get()); } -string FileSystem::NormalizeAbsolutePath(const string &path) { - D_ASSERT(IsPathAbsolute(path)); - return path; -} - #else string FileSystem::GetEnvVariable(const string &env) { @@ -226,17 +223,6 @@ bool FileSystem::IsPathAbsolute(const string &path) { return false; } -string FileSystem::NormalizeAbsolutePath(const string &path) { - D_ASSERT(IsPathAbsolute(path)); - auto result = FileSystem::ConvertSeparators(path); - if (StartsWithSingleBackslash(result)) { - // Path starts with a single backslash or forward slash - // prepend drive letter - return GetWorkingDirectory().substr(0, 2) + result; - } - return result; -} - string FileSystem::PathSeparator(const string &path) { if (StringUtil::StartsWith(path, "file:")) { return "/"; @@ -363,6 +349,43 @@ string FileSystem::GetHomeDirectory() { return GetHomeDirectory(nullptr); } +// Helper function to handle file:/ URLs +static idx_t GetFileUrlOffset(const string &path) { + if (!StringUtil::StartsWith(path, "file:/")) { + return 0; + } + + // Url without host: file:/some/path + if (path[6] != '/') { +#ifdef _WIN32 + return 6; +#else + return 5; +#endif + } + + // Url with empty host: file:///some/path + if (path[7] == '/') { +#ifdef _WIN32 + return 8; +#else + return 7; +#endif + } + + // Url with localhost: file://localhost/some/path + if (path.compare(7, 10, "localhost/") == 0) { +#ifdef _WIN32 + return 17; +#else + return 16; +#endif + } + + // unkown file:/ url format + return 0; +} + string FileSystem::ExpandPath(const string &path, optional_ptr opener) { if (path.empty()) { return path; @@ -370,6 +393,11 @@ string FileSystem::ExpandPath(const string &path, optional_ptr opene if (path[0] == '~') { return GetHomeDirectory(opener) + path.substr(1); } + // handle file URIs + auto file_offset = GetFileUrlOffset(path); + if (file_offset > 0) { + return path.substr(file_offset); + } return path; } @@ -412,6 +440,10 @@ bool FileSystem::SupportsListFilesExtended() const { return false; } +bool FileSystem::SupportsGlobExtended() const { + return false; +} + void FileSystem::Read(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) { throw NotImplementedException("%s: Read (with location) is not implemented!", GetName()); } @@ -600,9 +632,28 @@ bool FileSystem::HasGlob(const string &str) { } vector FileSystem::Glob(const string &path, FileOpener *opener) { + if (SupportsGlobExtended()) { + auto result = GlobFilesExtended(path, FileGlobOptions::ALLOW_EMPTY, opener); + return result->GetAllFiles(); + } throw NotImplementedException("%s: Glob is not implemented!", GetName()); } +unique_ptr FileSystem::Glob(const string &path, const FileGlobInput &input, + optional_ptr opener) { + if (!SupportsGlobExtended()) { + auto result = Glob(path, opener.get()); + return make_uniq(std::move(result)); + } else { + return GlobFilesExtended(path, input, opener); + } +} + +unique_ptr FileSystem::GlobFilesExtended(const string &path, const FileGlobInput &input, + optional_ptr opener) { + throw NotImplementedException("%s: GlobFilesExtended is not implemented!", GetName()); +} + void FileSystem::RegisterSubSystem(unique_ptr sub_fs) { throw NotImplementedException("%s: Can't register a sub system on a non-virtual file system", GetName()); } @@ -639,9 +690,9 @@ bool FileSystem::CanHandleFile(const string &fpath) { throw NotImplementedException("%s: CanHandleFile is not implemented!", GetName()); } -vector FileSystem::GlobFiles(const string &pattern, ClientContext &context, const FileGlobInput &input) { - auto result = Glob(pattern); - if (result.empty()) { +unique_ptr FileSystem::GlobFileList(const string &pattern, const FileGlobInput &input) { + auto result = GlobFilesExtended(pattern, input); + if (result->IsEmpty()) { if (input.behavior == FileGlobOptions::FALLBACK_GLOB && !HasGlob(pattern)) { // if we have no glob in the pattern and we have an extension, we try to glob if (!HasGlob(pattern)) { @@ -649,8 +700,8 @@ vector FileSystem::GlobFiles(const string &pattern, ClientContext throw InternalException("FALLBACK_GLOB requires an extension to be specified"); } string new_pattern = JoinPath(JoinPath(pattern, "**"), "*." + input.extension); - result = GlobFiles(new_pattern, context, FileGlobOptions::ALLOW_EMPTY); - if (!result.empty()) { + result = GlobFileList(new_pattern, FileGlobOptions::ALLOW_EMPTY); + if (!result->IsEmpty()) { // we found files by globbing the target as if it was a directory - return them return result; } @@ -663,6 +714,11 @@ vector FileSystem::GlobFiles(const string &pattern, ClientContext return result; } +vector FileSystem::GlobFiles(const string &pattern, const FileGlobInput &input) { + auto file_list = GlobFileList(pattern, input); + return file_list->GetAllFiles(); +} + void FileSystem::Seek(FileHandle &handle, idx_t location) { throw NotImplementedException("%s: Seek is not implemented!", GetName()); } @@ -859,4 +915,43 @@ bool FileSystem::IsRemoteFile(const string &path, string &extension) { return false; } +string FileSystem::CanonicalizePath(const string &path_p, optional_ptr opener) { + if (IsRemoteFile(path_p)) { + // don't canonicalize remote paths + return path_p; + } + auto path_sep = PathSeparator(path_p); + auto elements = StringUtil::Split(path_p, path_sep); + + deque path_stack; + string result; + for (idx_t i = 0; i < elements.size(); i++) { + if (elements[i].empty() || elements[i] == ".") { + // we ignore empty and `.` + continue; + } + if (elements[i] == "..") { + // .. pops from stack if possible, if already at root its ignored + if (!path_stack.empty()) { + path_stack.pop_back(); + } + } else { + path_stack.push_back(elements[i]); + } + } + // we lost the leading / in the split/loop so lets put it back + if (path_p[0] == '/') { + result = "/"; + } + while (!path_stack.empty()) { + result += path_stack.front(); + path_stack.pop_front(); + if (!path_stack.empty()) { + result += path_sep; + } + } + + return result; +} + } // namespace duckdb diff --git a/src/duckdb/src/common/hive_partitioning.cpp b/src/duckdb/src/common/hive_partitioning.cpp index 78f3b40e8..a4ae9486a 100644 --- a/src/duckdb/src/common/hive_partitioning.cpp +++ b/src/duckdb/src/common/hive_partitioning.cpp @@ -126,7 +126,7 @@ std::map HivePartitioning::Parse(const string &filename) { Value HivePartitioning::GetValue(ClientContext &context, const string &key, const string &str_val, const LogicalType &type) { // Handle nulls - if (StringUtil::CIEquals(str_val, "NULL")) { + if (StringUtil::CIEquals(str_val, "NULL") || str_val == "__HIVE_DEFAULT_PARTITION__") { return Value(type); } if (type.id() == LogicalTypeId::VARCHAR) { @@ -244,26 +244,13 @@ static void TemplatedGetHivePartitionValues(Vector &input, vector(data[sel.get_index(0)]).GetTypeMutable() != type; - if (reinterpret) { - for (idx_t i = 0; i < count; i++) { - auto &key = keys[i]; - const auto idx = sel.get_index(i); - if (validity.RowIsValid(idx)) { - key.values[col_idx] = GetHiveKeyValue(data[idx], type); - } else { - key.values[col_idx] = GetHiveKeyNullValue(type); - } - } - } else { - for (idx_t i = 0; i < count; i++) { - auto &key = keys[i]; - const auto idx = sel.get_index(i); - if (validity.RowIsValid(idx)) { - key.values[col_idx] = GetHiveKeyValue(data[idx]); - } else { - key.values[col_idx] = GetHiveKeyNullValue(type); - } + for (idx_t i = 0; i < count; i++) { + auto &key = keys[i]; + const auto idx = sel.get_index(i); + if (validity.RowIsValid(idx)) { + key.values[col_idx] = GetHiveKeyValue(data[idx], type); + } else { + key.values[col_idx] = GetHiveKeyNullValue(type); } } } diff --git a/src/duckdb/src/common/local_file_system.cpp b/src/duckdb/src/common/local_file_system.cpp index 3d9cae503..db5352f9e 100644 --- a/src/duckdb/src/common/local_file_system.cpp +++ b/src/duckdb/src/common/local_file_system.cpp @@ -11,6 +11,7 @@ #include "duckdb/main/database.hpp" #include "duckdb/logging/file_system_logger.hpp" #include "duckdb/logging/log_manager.hpp" +#include "duckdb/common/multi_file/multi_file_list.hpp" #include #include @@ -64,10 +65,10 @@ namespace duckdb { #ifndef _WIN32 bool LocalFileSystem::FileExists(const string &filename, optional_ptr opener) { if (!filename.empty()) { - auto normalized_file = NormalizeLocalPath(filename); - if (access(normalized_file, 0) == 0) { + auto normalized_file = ExpandPath(filename, opener); + if (access(normalized_file.c_str(), 0) == 0) { struct stat status; - stat(normalized_file, &status); + stat(normalized_file.c_str(), &status); if (S_ISREG(status.st_mode)) { return true; } @@ -79,10 +80,10 @@ bool LocalFileSystem::FileExists(const string &filename, optional_ptr opener) { if (!filename.empty()) { - auto normalized_file = NormalizeLocalPath(filename); - if (access(normalized_file, 0) == 0) { + auto normalized_file = ExpandPath(filename, opener); + if (access(normalized_file.c_str(), 0) == 0) { struct stat status; - stat(normalized_file, &status); + stat(normalized_file.c_str(), &status); if (S_ISFIFO(status.st_mode)) { return true; } @@ -93,21 +94,18 @@ bool LocalFileSystem::IsPipe(const string &filename, optional_ptr op } #else -static std::wstring NormalizePathAndConvertToUnicode(const string &path) { - string normalized_path_copy; - const char *normalized_path; - if (StringUtil::StartsWith(path, "file:/")) { - normalized_path_copy = LocalFileSystem::NormalizeLocalPath(path); - normalized_path_copy = LocalFileSystem().ConvertSeparators(normalized_path_copy); - normalized_path = normalized_path_copy.c_str(); - } else { - normalized_path = path.c_str(); - } - return WindowsUtil::UTF8ToUnicode(normalized_path); +static std::wstring ConvertPathToUnicode(const string &path) { + return WindowsUtil::UTF8ToUnicode(path.c_str()); +} + +static std::wstring NormalizePathAndConvertToUnicode(FileSystem &fs, const string &path, + optional_ptr opener) { + auto normalized_path = fs.ExpandPath(path, opener); + return ConvertPathToUnicode(normalized_path); } bool LocalFileSystem::FileExists(const string &filename, optional_ptr opener) { - auto unicode_path = NormalizePathAndConvertToUnicode(filename); + auto unicode_path = NormalizePathAndConvertToUnicode(*this, filename, opener); const wchar_t *wpath = unicode_path.c_str(); if (_waccess(wpath, 0) == 0) { struct _stati64 status; @@ -119,7 +117,7 @@ bool LocalFileSystem::FileExists(const string &filename, optional_ptr opener) { - auto unicode_path = NormalizePathAndConvertToUnicode(filename); + auto unicode_path = NormalizePathAndConvertToUnicode(*this, filename, opener); const wchar_t *wpath = unicode_path.c_str(); if (_waccess(wpath, 0) == 0) { struct _stati64 status; @@ -297,14 +295,13 @@ static string AdditionalProcessInfo(FileSystem &fs, pid_t pid) { bool LocalFileSystem::IsPrivateFile(const string &path_p, FileOpener *opener) { auto path = FileSystem::ExpandPath(path_p, opener); - auto normalized_path = NormalizeLocalPath(path); struct stat st; - if (lstat(normalized_path, &st) != 0) { + if (lstat(path.c_str(), &st) != 0) { throw IOException( "Failed to stat '%s' when checking file permissions, file may be missing or have incorrect permissions", - path.c_str()); + path_p.c_str()); } // If group or other have any permission, the file is not private @@ -317,8 +314,7 @@ bool LocalFileSystem::IsPrivateFile(const string &path_p, FileOpener *opener) { unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenFlags flags, optional_ptr opener) { - auto path = FileSystem::ExpandPath(path_p, opener); - auto normalized_path = NormalizeLocalPath(path); + auto path = ExpandPath(path_p, opener); if (flags.Compression() != FileCompressionType::UNCOMPRESSED) { throw NotImplementedException("Unsupported compression type for default file system"); } @@ -376,7 +372,7 @@ unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenF } // Open the file - int fd = open(normalized_path, open_flags, filesec); + int fd = open(path.c_str(), open_flags, filesec); if (fd == -1) { if (flags.ReturnNullIfNotExists() && errno == ENOENT) { @@ -621,10 +617,10 @@ void LocalFileSystem::Truncate(FileHandle &handle, int64_t new_size) { bool LocalFileSystem::DirectoryExists(const string &directory, optional_ptr opener) { if (!directory.empty()) { - auto normalized_dir = NormalizeLocalPath(directory); - if (access(normalized_dir, 0) == 0) { + auto normalized_dir = ExpandPath(directory, opener); + if (access(normalized_dir.c_str(), 0) == 0) { struct stat status; - stat(normalized_dir, &status); + stat(normalized_dir.c_str(), &status); if (S_ISDIR(status.st_mode)) { return true; } @@ -637,10 +633,10 @@ bool LocalFileSystem::DirectoryExists(const string &directory, optional_ptr opener) { struct stat st; - auto normalized_dir = NormalizeLocalPath(directory); - if (stat(normalized_dir, &st) != 0) { + auto normalized_dir = ExpandPath(directory, opener); + if (stat(normalized_dir.c_str(), &st) != 0) { /* Directory does not exist. EEXIST for race condition */ - if (mkdir(normalized_dir, 0755) != 0 && errno != EEXIST) { + if (mkdir(normalized_dir.c_str(), 0755) != 0 && errno != EEXIST) { throw IOException({{"errno", std::to_string(errno)}}, "Failed to create directory \"%s\": %s", directory, strerror(errno)); } @@ -691,13 +687,13 @@ int RemoveDirectoryRecursive(const char *path) { } void LocalFileSystem::RemoveDirectory(const string &directory, optional_ptr opener) { - auto normalized_dir = NormalizeLocalPath(directory); - RemoveDirectoryRecursive(normalized_dir); + auto normalized_dir = ExpandPath(directory, opener); + RemoveDirectoryRecursive(normalized_dir.c_str()); } void LocalFileSystem::RemoveFile(const string &filename, optional_ptr opener) { - auto normalized_file = NormalizeLocalPath(filename); - if (std::remove(normalized_file) != 0) { + auto normalized_file = ExpandPath(filename, opener); + if (std::remove(normalized_file.c_str()) != 0) { throw IOException({{"errno", std::to_string(errno)}}, "Could not remove file \"%s\": %s", filename, strerror(errno)); } @@ -706,8 +702,8 @@ void LocalFileSystem::RemoveFile(const string &filename, optional_ptr &callback, optional_ptr opener) { - auto normalized_dir = NormalizeLocalPath(directory); - auto dir = opendir(normalized_dir); + auto normalized_dir = ExpandPath(directory, opener); + auto dir = opendir(normalized_dir.c_str()); if (!dir) { return false; } @@ -784,11 +780,12 @@ void LocalFileSystem::FileSync(FileHandle &handle) { } void LocalFileSystem::MoveFile(const string &source, const string &target, optional_ptr opener) { - auto normalized_source = NormalizeLocalPath(source); - auto normalized_target = NormalizeLocalPath(target); + auto normalized_source = ExpandPath(source, opener); + auto normalized_target = ExpandPath(target, opener); //! FIXME: rename does not guarantee atomicity or overwriting target file if it exists - if (rename(normalized_source, normalized_target) != 0) { - throw IOException({{"errno", std::to_string(errno)}}, "Could not rename file!"); + if (rename(normalized_source.c_str(), normalized_target.c_str()) != 0) { + throw IOException({{"errno", to_string(errno)}}, "Could not rename file \"%s\" to \"%s\": %s", source, target, + strerror(errno)); } } @@ -796,6 +793,33 @@ std::string LocalFileSystem::GetLastErrorAsString() { return string(); } +bool LocalFileSystem::TryCanonicalizeExistingPath(string &input) { + char resolved[PATH_MAX]; + if (!realpath(input.c_str(), resolved)) { + return false; + } + input = resolved; + return true; +} + +bool LocalFileSystem::PathStartsWithDrive(const string &path) { + return false; +} + +bool LocalFileSystem::IsPathAbsolute(const string &path) { + return FileSystem::IsPathAbsolute(path); +} + +string LocalFileSystem::MakePathAbsolute(const string &path_p, optional_ptr opener) { + auto path = ExpandPath(path_p, opener); + if (!IsPathAbsolute(path)) { + // path is not absolute - join with working directory + return JoinPath(GetWorkingDirectory(), path); + } else { + // already absolute + return path; + } +} #else constexpr char PIPE_PREFIX[] = "\\\\.\\pipe\\"; @@ -987,7 +1011,7 @@ bool LocalFileSystem::IsPrivateFile(const string &path_p, FileOpener *opener) { unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenFlags flags, optional_ptr opener) { auto path = FileSystem::ExpandPath(path_p, opener); - auto unicode_path = NormalizePathAndConvertToUnicode(path); + auto unicode_path = NormalizePathAndConvertToUnicode(*this, path, opener); if (flags.Compression() != FileCompressionType::UNCOMPRESSED) { throw NotImplementedException("Unsupported compression type for default file system"); } @@ -1190,8 +1214,8 @@ void LocalFileSystem::Truncate(FileHandle &handle, int64_t new_size) { } } -static DWORD WindowsGetFileAttributes(const string &filename) { - auto unicode_path = NormalizePathAndConvertToUnicode(filename); +static DWORD WindowsGetFileAttributes(LocalFileSystem &fs, const string &filename, optional_ptr opener) { + auto unicode_path = NormalizePathAndConvertToUnicode(fs, filename, opener); return GetFileAttributesW(unicode_path.c_str()); } @@ -1200,7 +1224,7 @@ static DWORD WindowsGetFileAttributes(const std::wstring &filename) { } bool LocalFileSystem::DirectoryExists(const string &directory, optional_ptr opener) { - DWORD attrs = WindowsGetFileAttributes(directory); + DWORD attrs = WindowsGetFileAttributes(*this, directory, opener); return (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)); } @@ -1208,22 +1232,22 @@ void LocalFileSystem::CreateDirectory(const string &directory, optional_ptr opener) { fs.ListFiles(directory, [&](const string &fname, bool is_directory) { if (is_directory) { - DeleteDirectoryRecursive(fs, fs.JoinPath(directory, fname)); + DeleteDirectoryRecursive(fs, fs.JoinPath(directory, fname), opener); } else { fs.RemoveFile(fs.JoinPath(directory, fname)); } }); - auto unicode_path = NormalizePathAndConvertToUnicode(directory); + auto unicode_path = NormalizePathAndConvertToUnicode(fs, directory, opener); if (!RemoveDirectoryW(unicode_path.c_str())) { auto error = LocalFileSystem::GetLastErrorAsString(); throw IOException("Failed to delete directory \"%s\": %s", directory, error); @@ -1237,11 +1261,11 @@ void LocalFileSystem::RemoveDirectory(const string &directory, optional_ptr opener) { - auto unicode_path = NormalizePathAndConvertToUnicode(filename); + auto unicode_path = NormalizePathAndConvertToUnicode(*this, filename, opener); if (!DeleteFileW(unicode_path.c_str())) { auto error = LocalFileSystem::GetLastErrorAsString(); throw IOException("Failed to delete file \"%s\": %s", filename, error); @@ -1252,7 +1276,7 @@ bool LocalFileSystem::ListFilesExtended(const string &directory, const std::function &callback, optional_ptr opener) { string search_dir = JoinPath(directory, "*"); - auto unicode_path = NormalizePathAndConvertToUnicode(search_dir); + auto unicode_path = NormalizePathAndConvertToUnicode(*this, search_dir, opener); WIN32_FIND_DATAW ffd; HANDLE hFind = FindFirstFileW(unicode_path.c_str(), &ffd); @@ -1301,8 +1325,8 @@ void LocalFileSystem::FileSync(FileHandle &handle) { } void LocalFileSystem::MoveFile(const string &source, const string &target, optional_ptr opener) { - auto source_unicode = NormalizePathAndConvertToUnicode(source); - auto target_unicode = NormalizePathAndConvertToUnicode(target); + auto source_unicode = NormalizePathAndConvertToUnicode(*this, source, opener); + auto target_unicode = NormalizePathAndConvertToUnicode(*this, target, opener); DWORD flags = MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH; if (!MoveFileExW(source_unicode.c_str(), target_unicode.c_str(), flags)) { @@ -1320,6 +1344,75 @@ FileMetadata LocalFileSystem::Stats(FileHandle &handle) { auto file_metadata = StatsInternal(hFile, handle.GetPath()); return file_metadata; } + +bool LocalFileSystem::TryCanonicalizeExistingPath(string &input) { + auto unicode_path = ConvertPathToUnicode(input); + HANDLE handle = CreateFileW(unicode_path.c_str(), + 0, // No access needed, just query + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, // Required for directories + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + return false; + } + wchar_t resolved[MAX_PATH]; + DWORD len = GetFinalPathNameByHandleW(handle, resolved, MAX_PATH, FILE_NAME_NORMALIZED); + CloseHandle(handle); + + if (len < 0 && len >= MAX_PATH) { + return false; + } + input = WindowsUtil::UnicodeToUTF8(resolved); + return true; +} + +bool LocalFileSystem::PathStartsWithDrive(const string &path) { + return path.size() >= 2 && path[0] >= 'A' && path[0] <= 'Z' && path[1] == ':'; +} + +bool LocalFileSystem::IsPathAbsolute(const string &path) { + if (FileSystem::IsPathAbsolute(path)) { + return true; + } + // check if this is a drive letter (e.g. C:) + if (PathStartsWithDrive(path)) { + return true; + } + return false; +} + +string LocalFileSystem::MakePathAbsolute(const string &path_p, optional_ptr opener) { + auto path = ExpandPath(path_p, opener); + if (FileSystem::IsPathAbsolute(path)) { + // already absolute - nothing to do + return path; + } + // check if this is a drive letter (e.g. C:) + if (PathStartsWithDrive(path)) { + // this starts with a drive letter + // we now have two options - either this is "C:" or this is "C:\" + // "C:" is the current working directory, C:\ is an absolute path + if (path.size() >= 3 && (path[2] == '\\' || path[2] == '/')) { + // C:\\ - this is already an absolute path + return path; + } + // this is "C:" - expand to current working directory if this is the current drive + auto working_directory = GetWorkingDirectory(); + if (working_directory[0] != path[0]) { + // this is not the drive we are on right now (e.g. referencing D: while in C:) + // default to root of drive + working_directory = string(1, path[0]) + ":\\"; + } + if (path.size() == 2) { + return working_directory; + } + return JoinPath(working_directory, path.substr(2)); + } + + return JoinPath(GetWorkingDirectory(), path); +} + #endif bool LocalFileSystem::CanSeek() { @@ -1330,6 +1423,83 @@ bool LocalFileSystem::OnDiskFile(FileHandle &handle) { return true; } +string LocalFileSystem::CanonicalizePath(const string &input, optional_ptr opener) { + auto path_sep = PathSeparator(input); + if (path_sep.size() != 1) { + throw InternalException("path separator can only be a single byte for local file systems"); + } + // make the path absolute + string path = MakePathAbsolute(input, opener); + + string current = path; + string remainder; + idx_t dot_dot_count = 0; + bool is_drive = false; + while (!current.empty()) { + if (dot_dot_count == 0 && TryCanonicalizeExistingPath(current)) { + // successfully canonicalized "current" - add remainder if we have any + if (remainder.empty()) { + return current; + } + if (StringUtil::EndsWith(current, path_sep)) { + return current + remainder; + } + return current + path_sep + remainder; + } + if (is_drive) { + // this is a drive only (e.g. C:\) + // if we reach this, this is an unknown drive letter + // use fallback canonicalize for the remainder + return current + FileSystem::CanonicalizePath(remainder); + } + // move up one directory + optional_idx sep_idx; + for (idx_t i = current.size(); i > 0; i--) { + // on windows we accept both separators (\ and /, and also :) + if (current[i - 1] == path_sep[0] || current[i - 1] == '/') { + sep_idx = i - 1; + break; + } + } + if (!sep_idx.IsValid()) { + // exhausted the full path and nothing exists - break out + current = string(); + break; + } + auto sep = sep_idx.GetIndex(); + auto component = current.substr(sep + 1); + if (component == "..") { + // dot dot - we need to move up a level + // increment the count + dot_dot_count++; + } else if (!component.empty() && component != ".") { + if (dot_dot_count > 0) { + // just clear this directory + dot_dot_count--; + } else { + // add component to remainder - unless it's dot or empty + if (remainder.empty()) { + remainder = component; + } else { + remainder = component + path_sep + remainder; + } + } + } + // continue with remainder + current = current.substr(0, sep); + if (current.size() == 2 && PathStartsWithDrive(current)) { + // Windows only + // C: and C:\\ mean different things (C: is relative, C:\\ is absolute) + // we should have already normalized to C:\\ earlier on in this function + // so turn this base drive letter into C:\\ for the final lookup + is_drive = true; + current += "\\"; + } + } + // failed to canonicalize path - fallback to generic canonicalization + return FileSystem::CanonicalizePath(path); +} + string LocalFileSystem::GetVersionTag(FileHandle &handle) { // TODO: Fix using FileSystem::Stats for v1.5, which should also fix it for Windows #ifdef _WIN32 @@ -1370,61 +1540,23 @@ static bool IsCrawl(const string &glob) { // glob must match exactly return glob == "**"; } -static bool HasMultipleCrawl(const vector &splits) { - return std::count(splits.begin(), splits.end(), "**") > 1; -} + static bool IsSymbolicLink(const string &path) { - auto normalized_path = LocalFileSystem::NormalizeLocalPath(path); #ifndef _WIN32 struct stat status; - return (lstat(normalized_path, &status) != -1 && S_ISLNK(status.st_mode)); + return (lstat(path.c_str(), &status) != -1 && S_ISLNK(status.st_mode)); #else - auto attributes = WindowsGetFileAttributes(path); - if (attributes == INVALID_FILE_ATTRIBUTES) + auto unicode_path = ConvertPathToUnicode(path); + auto attributes = WindowsGetFileAttributes(unicode_path); + if (attributes == INVALID_FILE_ATTRIBUTES) { return false; + } return attributes & FILE_ATTRIBUTE_REPARSE_POINT; #endif } -static void RecursiveGlobDirectories(FileSystem &fs, const string &path, vector &result, - bool match_directory, bool join_path) { - fs.ListFiles(path, [&](OpenFileInfo &info) { - if (join_path) { - info.path = fs.JoinPath(path, info.path); - } - if (IsSymbolicLink(info.path)) { - return; - } - bool is_directory = FileSystem::IsDirectory(info); - bool return_file = is_directory == match_directory; - if (is_directory) { - if (return_file) { - result.push_back(info); - } - RecursiveGlobDirectories(fs, info.path, result, match_directory, true); - } else if (return_file) { - result.push_back(std::move(info)); - } - }); -} - -static void GlobFilesInternal(FileSystem &fs, const string &path, const string &glob, bool match_directory, - vector &result, bool join_path) { - fs.ListFiles(path, [&](OpenFileInfo &info) { - bool is_directory = FileSystem::IsDirectory(info); - if (is_directory != match_directory) { - return; - } - if (Glob(info.path.c_str(), info.path.size(), glob.c_str(), glob.size())) { - if (join_path) { - info.path = fs.JoinPath(path, info.path); - } - result.push_back(std::move(info)); - } - }); -} - -vector LocalFileSystem::FetchFileWithoutGlob(const string &path, FileOpener *opener, bool absolute_path) { +vector LocalFileSystem::FetchFileWithoutGlob(const string &path, optional_ptr opener, + bool absolute_path) { vector result; if (FileExists(path, opener) || IsPipe(path, opener)) { result.emplace_back(path); @@ -1444,59 +1576,96 @@ vector LocalFileSystem::FetchFileWithoutGlob(const string &path, F return result; } -// Helper function to handle file:/ URLs -static idx_t GetFileUrlOffset(const string &path) { - if (!StringUtil::StartsWith(path, "file:/")) { - return 0; +struct PathSplit { + PathSplit(LocalFileSystem &fs, string path_p) : path(std::move(path_p)), has_glob(fs.HasGlob(path)) { } - // Url without host: file:/some/path - if (path[6] != '/') { -#ifdef _WIN32 - return 6; -#else - return 5; -#endif + string path; + bool has_glob; +}; + +static bool HasMultipleCrawl(const vector &splits) { + idx_t crawl_count = 0; + for (auto &split : splits) { + if (split.path == "**") { + crawl_count++; + } } + return crawl_count > 1; +} - // Url with empty host: file:///some/path - if (path[7] == '/') { -#ifdef _WIN32 - return 8; -#else - return 7; -#endif +struct ExpandDirectory { + ExpandDirectory(string path_p, idx_t split_index, bool is_empty = false) + : path(std::move(path_p)), split_index(split_index), is_empty(is_empty) { } - // Url with localhost: file://localhost/some/path - if (path.compare(7, 10, "localhost/") == 0) { -#ifdef _WIN32 - return 17; -#else - return 16; -#endif + string path; + idx_t split_index; + bool is_empty = false; + + bool operator<(const ExpandDirectory &other) const { + return path > other.path; } +}; - // unkown file:/ url format - return 0; +static void CrawlDirectoryLevel(FileSystem &fs, const string &path, optional_ptr> files, + std::priority_queue &directories, idx_t split_index) { + fs.ListFiles(path, [&](OpenFileInfo &info) { + info.path = fs.JoinPath(path, info.path); + if (IsSymbolicLink(info.path)) { + return; + } + bool is_directory = FileSystem::IsDirectory(info); + if (is_directory) { + directories.emplace(std::move(info.path), split_index); + } else if (files) { + files->push_back(std::move(info)); + } + }); } -const char *LocalFileSystem::NormalizeLocalPath(const string &path) { - return path.c_str() + GetFileUrlOffset(path); +static void GlobFilesInternal(FileSystem &fs, const string &path, const string &glob, bool match_directory, + vector &result) { + fs.ListFiles(path, [&](OpenFileInfo &info) { + bool is_directory = FileSystem::IsDirectory(info); + if (is_directory != match_directory) { + return; + } + if (Glob(info.path.c_str(), info.path.size(), glob.c_str(), glob.size())) { + info.path = fs.JoinPath(path, info.path); + result.push_back(std::move(info)); + } + }); } -vector LocalFileSystem::Glob(const string &path, FileOpener *opener) { +struct LocalGlobResult : public LazyMultiFileList { +public: + LocalGlobResult(LocalFileSystem &fs, const string &path, FileGlobOptions options, optional_ptr opener); + +protected: + bool ExpandNextPath() const override; + +private: + LocalFileSystem &fs; + string path; + optional_ptr opener; + vector splits; + bool absolute_path = false; + mutable std::priority_queue expand_directories; + mutable bool finished = false; +}; + +LocalGlobResult::LocalGlobResult(LocalFileSystem &fs, const string &path_p, FileGlobOptions options_p, + optional_ptr opener) + : LazyMultiFileList(FileOpener::TryGetClientContext(opener)), fs(fs), path(fs.ExpandPath(path_p, opener)), + opener(opener) { if (path.empty()) { - return vector(); + finished = true; + return; } // split up the path into separate chunks - vector splits; - - bool is_file_url = StringUtil::StartsWith(path, "file:/"); - idx_t file_url_path_offset = GetFileUrlOffset(path); - idx_t last_pos = 0; - for (idx_t i = file_url_path_offset; i < path.size(); i++) { + for (idx_t i = 0; i < path.size(); i++) { if (path[i] == '\\' || path[i] == '/') { if (i == last_pos) { // empty: skip this position @@ -1504,129 +1673,151 @@ vector LocalFileSystem::Glob(const string &path, FileOpener *opene continue; } if (splits.empty()) { - // splits.push_back(path.substr(file_url_path_offset, i-file_url_path_offset)); - splits.push_back(path.substr(0, i)); + splits.emplace_back(fs, path.substr(0, i)); } else { - splits.push_back(path.substr(last_pos, i - last_pos)); + splits.emplace_back(fs, path.substr(last_pos, i - last_pos)); } last_pos = i + 1; } } - splits.push_back(path.substr(last_pos, path.size() - last_pos)); + splits.emplace_back(fs, path.substr(last_pos, path.size() - last_pos)); // handle absolute paths - bool absolute_path = false; - if (IsPathAbsolute(path)) { + absolute_path = false; + if (fs.IsPathAbsolute(path)) { // first character is a slash - unix absolute path absolute_path = true; - } else if (StringUtil::Contains(splits[0], ":")) { // TODO: this is weird? shouldn't IsPathAbsolute handle this? + } else if (StringUtil::Contains(splits[0].path, + ":")) { // TODO: this is weird? shouldn't IsPathAbsolute handle this? // first split has a colon - windows absolute path absolute_path = true; - } else if (splits[0] == "~") { + } else if (splits[0].path == "~") { // starts with home directory - auto home_directory = GetHomeDirectory(opener); + auto home_directory = fs.GetHomeDirectory(opener); if (!home_directory.empty()) { absolute_path = true; - splits[0] = home_directory; + splits[0].path = home_directory; D_ASSERT(path[0] == '~'); - if (!HasGlob(path)) { - return Glob(home_directory + path.substr(1)); + if (!fs.HasGlob(path)) { + expanded_files = fs.FetchFileWithoutGlob(home_directory + path.substr(1), opener, absolute_path); + finished = true; + return; } } } // Check if the path has a glob at all - if (!HasGlob(path)) { + if (!fs.HasGlob(path)) { // no glob: return only the file (if it exists or is a pipe) - return FetchFileWithoutGlob(path, opener, absolute_path); + expanded_files = fs.FetchFileWithoutGlob(path, opener, absolute_path); + finished = true; + return; } - vector previous_directories; if (absolute_path) { // for absolute paths, we don't start by scanning the current directory - previous_directories.push_back(splits[0]); + // FIXME: we don't support /[GLOB]/.. - i.e. globs in the first level of an absolute path + if (splits.size() > 1) { + expand_directories.emplace(splits[0].path, 1); + } } else { // If file_search_path is set, use those paths as the first glob elements Value value; if (opener && opener->TryGetCurrentSetting("file_search_path", value)) { auto search_paths_str = value.ToString(); - vector search_paths = StringUtil::Split(search_paths_str, ','); + auto search_paths = StringUtil::Split(search_paths_str, ','); for (const auto &search_path : search_paths) { - previous_directories.push_back(search_path); + expand_directories.emplace(search_path, 0); } } + if (expand_directories.empty()) { + expand_directories.emplace(".", 0, true); + } } if (HasMultipleCrawl(splits)) { throw IOException("Cannot use multiple \'**\' in one path"); } +} + +bool LocalGlobResult::ExpandNextPath() const { + if (finished) { + return false; + } + if (expand_directories.empty()) { + if (expanded_files.empty()) { + // no result found that matches the glob + // last ditch effort: search the path as a string literal + expanded_files = fs.FetchFileWithoutGlob(path, opener, absolute_path); + } + finished = true; + return false; + } - idx_t start_index; - if (is_file_url) { - start_index = 1; - } else if (absolute_path) { - start_index = 1; + auto next_dir = expand_directories.top(); + auto is_empty = next_dir.is_empty; + auto split_index = next_dir.split_index; + auto ¤t_path = next_dir.path; + expand_directories.pop(); + + auto &next_split = splits[split_index]; + bool is_last_component = split_index + 1 == splits.size(); + auto &next_component = next_split.path; + bool has_glob = next_split.has_glob; + // if it's the last chunk we need to find files, otherwise we find directories + // not the last chunk: gather a list of all directories that match the glob pattern + if (!has_glob) { + // no glob, just append as-is + if (is_empty) { + if (is_last_component) { + throw InternalException("No glob in only component - but entire split has globs?"); + } + // no path yet - just append + expand_directories.emplace(next_component, split_index + 1); + } else { + if (is_last_component) { + // last component - we are emitting a result here + auto filename = fs.JoinPath(current_path, next_component); + if (fs.FileExists(filename, opener) || fs.DirectoryExists(filename, opener)) { + expanded_files.emplace_back(std::move(filename)); + } + } else { + // not the last component - add the next directory as "to-be-expanded" + expand_directories.emplace(fs.JoinPath(current_path, next_component), split_index + 1); + } + } } else { - start_index = 0; - } - - for (idx_t i = start_index ? 1 : 0; i < splits.size(); i++) { - bool is_last_chunk = i + 1 == splits.size(); - bool has_glob = HasGlob(splits[i]); - // if it's the last chunk we need to find files, otherwise we find directories - // not the last chunk: gather a list of all directories that match the glob pattern - vector result; - if (!has_glob) { - // no glob, just append as-is - if (previous_directories.empty()) { - result.push_back(splits[i]); + // glob - need to resolve the glob + if (IsCrawl(next_component)) { + if (is_last_component) { + // the crawl is the last component - we are looking for files in this directory + // any directories we encounter are added to the expand directories + CrawlDirectoryLevel(fs, current_path, expanded_files, expand_directories, split_index); } else { - if (is_last_chunk) { - for (auto &prev_directory : previous_directories) { - const string filename = JoinPath(prev_directory.path, splits[i]); - if (FileExists(filename, opener) || DirectoryExists(filename, opener)) { - result.push_back(filename); - } - } - } else { - for (auto &prev_directory : previous_directories) { - result.push_back(JoinPath(prev_directory.path, splits[i])); - } - } + // not the last crawl + // ** also matches the current directory (i.e. dir/**/file.parquet also matches dir/file.parquet) + expand_directories.emplace(current_path, split_index + 1); + // now crawl the contents of this directory - but don't add any files we find + CrawlDirectoryLevel(fs, current_path, nullptr, expand_directories, split_index); } } else { - if (IsCrawl(splits[i])) { - if (!is_last_chunk) { - result = previous_directories; - } - if (previous_directories.empty()) { - RecursiveGlobDirectories(*this, ".", result, !is_last_chunk, false); - } else { - for (auto &prev_dir : previous_directories) { - RecursiveGlobDirectories(*this, prev_dir.path, result, !is_last_chunk, true); - } - } + // glob this directory according to the next component + if (is_last_component) { + // last component - match files and place them in the result + GlobFilesInternal(fs, current_path, next_component, false, expanded_files); } else { - if (previous_directories.empty()) { - // no previous directories: list in the current path - GlobFilesInternal(*this, ".", splits[i], !is_last_chunk, result, false); - } else { - // previous directories - // we iterate over each of the previous directories, and apply the glob of the current directory - for (auto &prev_directory : previous_directories) { - GlobFilesInternal(*this, prev_directory.path, splits[i], !is_last_chunk, result, true); - } + // not the last component - match directories and add to expansion list + vector child_directories; + GlobFilesInternal(fs, current_path, next_component, true, child_directories); + for (auto &file : child_directories) { + expand_directories.emplace(std::move(file.path), split_index + 1); } } } - if (result.empty()) { - // no result found that matches the glob - // last ditch effort: search the path as a string literal - return FetchFileWithoutGlob(path, opener, absolute_path); - } - if (is_last_chunk) { - return result; - } - previous_directories = std::move(result); } - return vector(); + return true; +} + +unique_ptr LocalFileSystem::GlobFilesExtended(const string &path, const FileGlobInput &input, + optional_ptr opener) { + return make_uniq(*this, path, FileGlobOptions::ALLOW_EMPTY, opener); } unique_ptr FileSystem::CreateLocal() { diff --git a/src/duckdb/src/common/multi_file/multi_file_list.cpp b/src/duckdb/src/common/multi_file/multi_file_list.cpp index 97e6addac..e39c92694 100644 --- a/src/duckdb/src/common/multi_file/multi_file_list.cpp +++ b/src/duckdb/src/common/multi_file/multi_file_list.cpp @@ -4,10 +4,9 @@ #include "duckdb/common/hive_partitioning.hpp" #include "duckdb/common/types.hpp" #include "duckdb/function/function_set.hpp" -#include "duckdb/function/table_function.hpp" #include "duckdb/main/config.hpp" #include "duckdb/planner/operator/logical_get.hpp" -#include "duckdb/common/string_util.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" #include @@ -79,14 +78,15 @@ bool PushdownInternal(ClientContext &context, const MultiFileOptions &options, c //===--------------------------------------------------------------------===// // MultiFileListIterator //===--------------------------------------------------------------------===// -MultiFileListIterationHelper MultiFileList::Files() { +MultiFileListIterationHelper MultiFileList::Files() const { return MultiFileListIterationHelper(*this); } -MultiFileListIterationHelper::MultiFileListIterationHelper(MultiFileList &file_list_p) : file_list(file_list_p) { +MultiFileListIterationHelper::MultiFileListIterationHelper(const MultiFileList &file_list_p) : file_list(file_list_p) { } -MultiFileListIterationHelper::MultiFileListIterator::MultiFileListIterator(MultiFileList *file_list_p) +MultiFileListIterationHelper::MultiFileListIterator::MultiFileListIterator( + optional_ptr file_list_p) : file_list(file_list_p) { if (!file_list) { return; @@ -136,27 +136,41 @@ const OpenFileInfo &MultiFileListIterationHelper::MultiFileListIterator::operato //===--------------------------------------------------------------------===// // MultiFileList //===--------------------------------------------------------------------===// -MultiFileList::MultiFileList(vector paths, FileGlobInput glob_input_p) - : paths(std::move(paths)), glob_input(std::move(glob_input_p)) { +MultiFileList::MultiFileList() { } -MultiFileList::MultiFileList(vector paths, FileGlobOptions options) - : MultiFileList(std::move(paths), FileGlobInput(options)) { +MultiFileList::~MultiFileList() { } -MultiFileList::~MultiFileList() { +void MultiFileList::InitializeScan(MultiFileListScanData &iterator) const { + iterator.current_file_idx = 0; } -const vector MultiFileList::GetPaths() const { - return paths; +vector MultiFileList::GetDisplayFileList(optional_idx max_files) const { + vector files; + for (idx_t i = 0;; i++) { + if (max_files.IsValid() && files.size() >= max_files.GetIndex()) { + break; + } + auto file = GetFile(i); + if (file.path.empty()) { + break; + } + files.push_back(std::move(file)); + } + return files; } -void MultiFileList::InitializeScan(MultiFileListScanData &iterator) { - iterator.current_file_idx = 0; +MultiFileCount MultiFileList::GetFileCount(idx_t min_exact_count) const { + return MultiFileCount(GetTotalFileCount()); } -bool MultiFileList::Scan(MultiFileListScanData &iterator, OpenFileInfo &result_file) { +bool MultiFileList::Scan(MultiFileListScanData &iterator, OpenFileInfo &result_file) const { D_ASSERT(iterator.current_file_idx != DConstants::INVALID_INDEX); + if (iterator.scan_type == MultiFileListScanType::FETCH_IF_AVAILABLE && + !FileIsAvailable(iterator.current_file_idx)) { + return false; + } auto maybe_file = GetFile(iterator.current_file_idx); if (maybe_file.path.empty()) { @@ -171,8 +185,17 @@ bool MultiFileList::Scan(MultiFileListScanData &iterator, OpenFileInfo &result_f unique_ptr MultiFileList::ComplexFilterPushdown(ClientContext &context, const MultiFileOptions &options, MultiFilePushdownInfo &info, - vector> &filters) { - // By default the filter pushdown into a multifilelist does nothing + vector> &filters) const { + if (!options.hive_partitioning && !options.filename) { + return nullptr; + } + + // FIXME: don't copy list until first file is filtered + auto file_copy = GetAllFiles(); + auto res = PushdownInternal(context, options, info, filters, file_copy); + if (res) { + return make_uniq(std::move(file_copy)); + } return nullptr; } @@ -181,75 +204,51 @@ unique_ptr MultiFileList::DynamicFilterPushdown(ClientContext &co const vector &types, const vector &column_ids, TableFilterSet &filters) const { - // By default the filter pushdown into a multifilelist does nothing + if (!options.hive_partitioning && !options.filename) { + return nullptr; + } + + // FIXME: don't copy list until first file is filtered + auto file_copy = GetAllFiles(); + auto res = PushdownInternal(context, options, names, types, column_ids, filters, file_copy); + if (res) { + return make_uniq(std::move(file_copy)); + } + return nullptr; } -unique_ptr MultiFileList::GetCardinality(ClientContext &context) { +unique_ptr MultiFileList::GetCardinality(ClientContext &context) const { return nullptr; } -OpenFileInfo MultiFileList::GetFirstFile() { +OpenFileInfo MultiFileList::GetFirstFile() const { return GetFile(0); } -bool MultiFileList::IsEmpty() { +bool MultiFileList::IsEmpty() const { return GetExpandResult() == FileExpandResult::NO_FILES; } -unique_ptr MultiFileList::Copy() { +unique_ptr MultiFileList::Copy() const { return make_uniq(GetAllFiles()); } +bool MultiFileList::FileIsAvailable(idx_t i) const { + return true; +} + //===--------------------------------------------------------------------===// // SimpleMultiFileList //===--------------------------------------------------------------------===// -SimpleMultiFileList::SimpleMultiFileList(vector paths_p) - : MultiFileList(std::move(paths_p), FileGlobOptions::ALLOW_EMPTY) { -} - -unique_ptr SimpleMultiFileList::ComplexFilterPushdown(ClientContext &context_p, - const MultiFileOptions &options, - MultiFilePushdownInfo &info, - vector> &filters) { - if (!options.hive_partitioning && !options.filename) { - return nullptr; - } - - // FIXME: don't copy list until first file is filtered - auto file_copy = paths; - auto res = PushdownInternal(context_p, options, info, filters, file_copy); - - if (res) { - return make_uniq(file_copy); - } - - return nullptr; -} - -unique_ptr -SimpleMultiFileList::DynamicFilterPushdown(ClientContext &context, const MultiFileOptions &options, - const vector &names, const vector &types, - const vector &column_ids, TableFilterSet &filters) const { - if (!options.hive_partitioning && !options.filename) { - return nullptr; - } - - // FIXME: don't copy list until first file is filtered - auto file_copy = paths; - auto res = PushdownInternal(context, options, names, types, column_ids, filters, file_copy); - if (res) { - return make_uniq(file_copy); - } - - return nullptr; +SimpleMultiFileList::SimpleMultiFileList(vector paths_p) : paths(std::move(paths_p)) { } -vector SimpleMultiFileList::GetAllFiles() { +vector SimpleMultiFileList::GetAllFiles() const { return paths; } -FileExpandResult SimpleMultiFileList::GetExpandResult() { +FileExpandResult SimpleMultiFileList::GetExpandResult() const { if (paths.size() > 1) { return FileExpandResult::MULTIPLE_FILES; } else if (paths.size() == 1) { @@ -259,7 +258,7 @@ FileExpandResult SimpleMultiFileList::GetExpandResult() { return FileExpandResult::NO_FILES; } -OpenFileInfo SimpleMultiFileList::GetFile(idx_t i) { +OpenFileInfo SimpleMultiFileList::GetFile(idx_t i) const { if (paths.empty() || i >= paths.size()) { return OpenFileInfo(""); } @@ -267,99 +266,61 @@ OpenFileInfo SimpleMultiFileList::GetFile(idx_t i) { return paths[i]; } -idx_t SimpleMultiFileList::GetTotalFileCount() { +idx_t SimpleMultiFileList::GetTotalFileCount() const { return paths.size(); } //===--------------------------------------------------------------------===// -// GlobMultiFileList +// LazyFileList //===--------------------------------------------------------------------===// -GlobMultiFileList::GlobMultiFileList(ClientContext &context_p, vector paths_p, FileGlobInput glob_input) - : MultiFileList(std::move(paths_p), std::move(glob_input)), context(context_p), current_path(0) { +LazyMultiFileList::LazyMultiFileList(optional_ptr context_p) : context(context_p) { } -unique_ptr GlobMultiFileList::ComplexFilterPushdown(ClientContext &context_p, - const MultiFileOptions &options, - MultiFilePushdownInfo &info, - vector> &filters) { +vector LazyMultiFileList::GetAllFiles() const { lock_guard lck(lock); - - // Expand all - // FIXME: lazy expansion - // FIXME: push down filters into glob - while (ExpandNextPath()) { - } - - if (!options.hive_partitioning && !options.filename) { - return nullptr; - } - auto res = PushdownInternal(context, options, info, filters, expanded_files); - if (res) { - return make_uniq(expanded_files); + while (ExpandNextPathInternal()) { } - - return nullptr; -} - -unique_ptr -GlobMultiFileList::DynamicFilterPushdown(ClientContext &context, const MultiFileOptions &options, - const vector &names, const vector &types, - const vector &column_ids, TableFilterSet &filters) const { - if (!options.hive_partitioning && !options.filename) { - return nullptr; - } - lock_guard lck(lock); - - // Expand all paths into a copy - // FIXME: lazy expansion and push filters into glob - idx_t path_index = current_path; - auto file_list = expanded_files; - while (ExpandPathInternal(path_index, file_list)) { - } - - auto res = PushdownInternal(context, options, names, types, column_ids, filters, file_list); - if (res) { - return make_uniq(file_list); - } - - return nullptr; + return expanded_files; } -vector GlobMultiFileList::GetAllFiles() { +idx_t LazyMultiFileList::GetTotalFileCount() const { lock_guard lck(lock); - while (ExpandNextPath()) { + while (ExpandNextPathInternal()) { } - return expanded_files; + return expanded_files.size(); } -idx_t GlobMultiFileList::GetTotalFileCount() { +MultiFileCount LazyMultiFileList::GetFileCount(idx_t min_exact_count) const { lock_guard lck(lock); - while (ExpandNextPath()) { + // expand files so that we get to min_exact_count + while (!all_files_expanded && expanded_files.size() < min_exact_count && ExpandNextPathInternal()) { } - return expanded_files.size(); + auto type = all_files_expanded ? FileExpansionType::ALL_FILES_EXPANDED : FileExpansionType::NOT_ALL_FILES_KNOWN; + return MultiFileCount(expanded_files.size(), type); } -FileExpandResult GlobMultiFileList::GetExpandResult() { +FileExpandResult LazyMultiFileList::GetExpandResult() const { // GetFile(1) will ensure at least the first 2 files are expanded if they are available - GetFile(1); + (void)GetFile(1); + lock_guard lck(lock); if (expanded_files.size() > 1) { return FileExpandResult::MULTIPLE_FILES; } else if (expanded_files.size() == 1) { return FileExpandResult::SINGLE_FILE; } - return FileExpandResult::NO_FILES; } -OpenFileInfo GlobMultiFileList::GetFile(idx_t i) { +bool LazyMultiFileList::FileIsAvailable(idx_t i) const { lock_guard lck(lock); - return GetFileInternal(i); + return i < expanded_files.size(); } -OpenFileInfo GlobMultiFileList::GetFileInternal(idx_t i) { +OpenFileInfo LazyMultiFileList::GetFile(idx_t i) const { + lock_guard lck(lock); while (expanded_files.size() <= i) { - if (!ExpandNextPath()) { + if (!ExpandNextPathInternal()) { return OpenFileInfo(""); } } @@ -367,26 +328,76 @@ OpenFileInfo GlobMultiFileList::GetFileInternal(idx_t i) { return expanded_files[i]; } -bool GlobMultiFileList::ExpandPathInternal(idx_t ¤t_path, vector &result) const { - if (current_path >= paths.size()) { +bool LazyMultiFileList::ExpandNextPathInternal() const { + if (all_files_expanded) { + return false; + } + if (context && context->interrupted) { + throw InterruptException(); + } + if (!ExpandNextPath()) { + all_files_expanded = true; return false; } - - auto &fs = FileSystem::GetFileSystem(context); - auto glob_files = fs.GlobFiles(paths[current_path].path, context, glob_input); - std::sort(glob_files.begin(), glob_files.end()); - result.insert(result.end(), glob_files.begin(), glob_files.end()); - - current_path++; return true; } -bool GlobMultiFileList::ExpandNextPath() { - return ExpandPathInternal(current_path, expanded_files); +//===--------------------------------------------------------------------===// +// GlobMultiFileList +//===--------------------------------------------------------------------===// +GlobMultiFileList::GlobMultiFileList(ClientContext &context_p, vector globs_p, FileGlobInput glob_input_p) + : LazyMultiFileList(&context_p), context(context_p), globs(std::move(globs_p)), glob_input(std::move(glob_input_p)), + current_glob(0) { +} + +vector GlobMultiFileList::GetDisplayFileList(optional_idx max_files) const { + // for globs we display the actual globs in the ToString() - instead of expanding to the files read + vector result; + for (auto &glob : globs) { + if (max_files.IsValid() && result.size() >= max_files.GetIndex()) { + break; + } + result.emplace_back(glob); + } + return result; } -bool GlobMultiFileList::IsFullyExpanded() const { - return current_path == paths.size(); +bool GlobMultiFileList::ExpandNextPath() const { + if (current_glob >= globs.size()) { + return false; + } + if (current_glob >= file_lists.size()) { + // glob is not yet started for this file - start it and initiate the scan over this file + auto &fs = FileSystem::GetFileSystem(context); + auto glob_result = fs.GlobFileList(globs[current_glob], glob_input); + scan_state = MultiFileListScanData(); + glob_result->InitializeScan(scan_state); + file_lists.push_back(std::move(glob_result)); + } + // get the next batch of files we can fetch through the glob + auto &glob_list = *file_lists[current_glob]; + scan_state.scan_type = MultiFileListScanType::ALWAYS_FETCH; + OpenFileInfo file; + if (!glob_list.Scan(scan_state, file)) { + // no more files available in this glob - move to the next glob + current_glob++; + return true; + } + // we found a file as part of this glob - add it to the result + vector glob_files; + glob_files.push_back(std::move(file)); + + // now continue scanning files that are already available (i.e. that don't require extra I/O operations to fetch) + scan_state.scan_type = MultiFileListScanType::FETCH_IF_AVAILABLE; + while (glob_list.Scan(scan_state, file)) { + glob_files.push_back(std::move(file)); + } + + // sort the files and add them to the list of files + std::sort(glob_files.begin(), glob_files.end()); + expanded_files.insert(expanded_files.end(), glob_files.begin(), glob_files.end()); + + return true; } } // namespace duckdb diff --git a/src/duckdb/src/common/multi_file/multi_file_reader.cpp b/src/duckdb/src/common/multi_file/multi_file_reader.cpp index d69e4a187..b5a160694 100644 --- a/src/duckdb/src/common/multi_file/multi_file_reader.cpp +++ b/src/duckdb/src/common/multi_file/multi_file_reader.cpp @@ -118,11 +118,7 @@ vector MultiFileReader::ParsePaths(const Value &input) { shared_ptr MultiFileReader::CreateFileList(ClientContext &context, const vector &paths, const FileGlobInput &glob_input) { - vector open_files; - for (auto &path : paths) { - open_files.emplace_back(path); - } - auto res = make_uniq(context, std::move(open_files), glob_input); + auto res = make_uniq(context, paths, glob_input); if (res->GetExpandResult() == FileExpandResult::NO_FILES && glob_input.behavior != FileGlobOptions::ALLOW_EMPTY) { throw IOException("%s needs at least one file to read", function_name); } diff --git a/src/duckdb/src/common/operator/cast_operators.cpp b/src/duckdb/src/common/operator/cast_operators.cpp index 5998d7787..233bcf619 100644 --- a/src/duckdb/src/common/operator/cast_operators.cpp +++ b/src/duckdb/src/common/operator/cast_operators.cpp @@ -26,6 +26,8 @@ #include "duckdb/common/operator/integer_cast_operator.hpp" #include "duckdb/common/operator/double_cast_operator.hpp" #include "duckdb/planner/expression.hpp" +#include "duckdb/common/serializer/binary_deserializer.hpp" +#include "duckdb/common/serializer/memory_stream.hpp" #include #include @@ -1424,6 +1426,22 @@ string_t CastFromPointer::Operation(uintptr_t input, Vector &vector) { return StringVector::AddString(vector, s); } +//===--------------------------------------------------------------------===// +// Cast From Pointer +//===--------------------------------------------------------------------===// +template <> +string_t CastFromType::Operation(string_t input, Vector &vector) { + MemoryStream stream(data_ptr_cast(input.GetDataWriteable()), input.GetSize()); + BinaryDeserializer deserializer(stream); + try { + auto type = LogicalType::Deserialize(deserializer); + return StringVector::AddString(vector, type.ToString()); + } catch (std::exception &ex) { + // TODO: Format better error here? + return StringVector::AddString(vector, ex.what()); + } +} + //===--------------------------------------------------------------------===// // Cast To Blob //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/common/string_util.cpp b/src/duckdb/src/common/string_util.cpp index 682a94392..9c8cf8295 100644 --- a/src/duckdb/src/common/string_util.cpp +++ b/src/duckdb/src/common/string_util.cpp @@ -77,6 +77,14 @@ idx_t StringUtil::ToUnsigned(const string &str) { return std::stoull(str); } +int64_t StringUtil::ToSigned(const string &str) { + return std::stoll(str); +} + +double StringUtil::ToDouble(const string &str) { + return std::stod(str); +} + void StringUtil::LTrim(string &str) { auto it = str.begin(); while (it != str.end() && CharacterIsSpace(*it)) { diff --git a/src/duckdb/src/common/thread_util.cpp b/src/duckdb/src/common/thread_util.cpp index 0860d6d2a..96a576e21 100644 --- a/src/duckdb/src/common/thread_util.cpp +++ b/src/duckdb/src/common/thread_util.cpp @@ -1,14 +1,45 @@ #include "duckdb/common/thread.hpp" #include "duckdb/common/chrono.hpp" +#include "duckdb/original/std/sstream.hpp" namespace duckdb { -void ThreadUtil::SleepMs(idx_t sleep_ms) { #ifndef DUCKDB_NO_THREADS +void ThreadUtil::SleepMs(idx_t sleep_ms) { std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms)); +} + +void ThreadUtil::SleepMicroSeconds(idx_t micros) { + std::this_thread::sleep_for(std::chrono::microseconds(micros)); +} + +thread_id ThreadUtil::GetThreadId() { + return std::this_thread::get_id(); +} + +string ThreadUtil::GetThreadIdString() { + std::ostringstream ss; + ss << std::this_thread::get_id(); + return ss.str(); +} + #else + +void ThreadUtil::SleepMs(idx_t sleep_ms) { throw InvalidInputException("ThreadUtil::SleepMs requires DuckDB to be compiled with thread support"); -#endif } +void ThreadUtil::SleepMicroSeconds(idx_t micros) { + throw InvalidInputException("ThreadUtil::SleepMicroSeconds requires DuckDB to be compiled with thread support"); +} + +thread_id ThreadUtil::GetThreadId() { + return 0; +} + +string ThreadUtil::GetThreadIdString() { + return "0"; +} + +#endif } // namespace duckdb diff --git a/src/duckdb/src/common/types.cpp b/src/duckdb/src/common/types.cpp index 83374d0de..6fa5e4509 100644 --- a/src/duckdb/src/common/types.cpp +++ b/src/duckdb/src/common/types.cpp @@ -17,15 +17,16 @@ #include "duckdb/common/types/vector.hpp" #include "duckdb/common/uhugeint.hpp" #include "duckdb/function/cast_rules.hpp" -#include "duckdb/main/attached_database.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/client_data.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/main/database.hpp" -#include "duckdb/main/database_manager.hpp" +#include "duckdb/common/types/type_manager.hpp" +#include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/keyword_helper.hpp" #include "duckdb/parser/parser.hpp" #include "duckdb/main/settings.hpp" +#include "duckdb/parser/expression/type_expression.hpp" +#include "duckdb/common/serializer/serializer.hpp" +#include "duckdb/common/serializer/deserializer.hpp" #include @@ -119,6 +120,7 @@ PhysicalType LogicalType::GetInternalType() { case LogicalTypeId::CHAR: case LogicalTypeId::BLOB: case LogicalTypeId::BIT: + case LogicalTypeId::TYPE: return PhysicalType::VARCHAR; case LogicalTypeId::INTERVAL: return PhysicalType::INTERVAL; @@ -158,7 +160,7 @@ PhysicalType LogicalType::GetInternalType() { case LogicalTypeId::INTEGER_LITERAL: case LogicalTypeId::TEMPLATE: return PhysicalType::INVALID; - case LogicalTypeId::USER: + case LogicalTypeId::UNBOUND: return PhysicalType::UNKNOWN; case LogicalTypeId::AGGREGATE_STATE: return PhysicalType::VARCHAR; @@ -387,7 +389,7 @@ static string TypeModifierListToString(const vector &mod_li } string LogicalType::ToString() const { - if (id_ != LogicalTypeId::USER) { + if (id_ != LogicalTypeId::UNBOUND) { auto alias = GetAlias(); if (!alias.empty()) { if (HasExtensionInfo()) { @@ -482,39 +484,17 @@ string LogicalType::ToString() const { ret += ")"; return ret; } - case LogicalTypeId::USER: { - string result; - auto &catalog = UserType::GetCatalog(*this); - auto &schema = UserType::GetSchema(*this); - auto &type = UserType::GetTypeName(*this); - auto &mods = UserType::GetTypeModifiers(*this); - - if (!catalog.empty()) { - result = KeywordHelper::WriteOptionallyQuoted(catalog); - } - if (!schema.empty()) { - if (!result.empty()) { - result += "."; - } - result += KeywordHelper::WriteOptionallyQuoted(schema); - } - if (!result.empty()) { - result += "."; - } - result += KeywordHelper::WriteOptionallyQuoted(type); - - if (!mods.empty()) { - result += "("; - for (idx_t i = 0; i < mods.size(); i++) { - result += mods[i].ToString(); - if (i < mods.size() - 1) { - result += ", "; - } - } - result += ")"; + case LogicalTypeId::UNBOUND: { + if (!type_info_) { + return "UNBOUND"; } - return result; + auto &expr = UnboundType::GetTypeExpression(*this); + if (expr->type != ExpressionType::TYPE) { + return "(" + expr->ToString() + ")"; + } else { + return expr->ToString(); + } } case LogicalTypeId::AGGREGATE_STATE: { return AggregateStateType::GetTypeName(*this); @@ -533,8 +513,8 @@ string LogicalType::ToString() const { return "GEOMETRY"; } auto &crs = GeoType::GetCRS(*this); - auto crs_name = KeywordHelper::WriteQuoted(crs.GetDisplayName(), '\''); - return StringUtil::Format("GEOMETRY(%s)", crs_name); + auto crs_text = KeywordHelper::WriteQuoted(crs.GetDefinition(), '\''); + return StringUtil::Format("GEOMETRY(%s)", crs_text); } default: return EnumUtil::ToString(id_); @@ -547,110 +527,13 @@ LogicalTypeId TransformStringToLogicalTypeId(const string &str) { if (type == LogicalTypeId::INVALID) { // This is a User Type, at this point we don't know if its one of the User Defined Types or an error // It is checked in the binder - type = LogicalTypeId::USER; + type = LogicalTypeId::UNBOUND; } return type; } -LogicalType TransformStringToLogicalType(const string &str) { - if (StringUtil::Lower(str) == "null") { - return LogicalType::SQLNULL; - } - ColumnList column_list; - try { - column_list = Parser::ParseColumnList("dummy " + str); - } catch (const std::runtime_error &e) { - const vector suggested_types {"BIGINT", - "INT8", - "LONG", - "BIT", - "BITSTRING", - "BLOB", - "BYTEA", - "BINARY,", - "VARBINARY", - "BOOLEAN", - "BOOL", - "LOGICAL", - "DATE", - "DECIMAL(prec, scale)", - "DOUBLE", - "FLOAT8", - "FLOAT", - "FLOAT4", - "REAL", - "HUGEINT", - "INTEGER", - "INT4", - "INT", - "SIGNED", - "INTERVAL", - "SMALLINT", - "INT2", - "SHORT", - "TIME", - "TIMESTAMPTZ", - "TIMESTAMP", - "DATETIME", - "TINYINT", - "INT1", - "UBIGINT", - "UHUGEINT", - "UINTEGER", - "USMALLINT", - "UTINYINT", - "UUID", - "VARCHAR", - "CHAR", - "BPCHAR", - "TEXT", - "STRING", - "MAP(INTEGER, VARCHAR)", - "UNION(num INTEGER, text VARCHAR)"}; - std::ostringstream error; - error << "Value \"" << str << "\" can not be converted to a DuckDB Type." << '\n'; - error << "Possible examples as suggestions: " << '\n'; - auto suggestions = StringUtil::TopNJaroWinkler(suggested_types, str); - for (auto &suggestion : suggestions) { - error << "* " << suggestion << '\n'; - } - throw InvalidInputException(error.str()); - } - return column_list.GetColumn(LogicalIndex(0)).Type(); -} - -LogicalType GetUserTypeRecursive(const LogicalType &type, ClientContext &context) { - if (type.id() == LogicalTypeId::USER && type.HasAlias()) { - auto &type_entry = - Catalog::GetEntry(context, INVALID_CATALOG, INVALID_SCHEMA, type.GetAlias()); - return type_entry.user_type; - } - // Look for LogicalTypeId::USER in nested types - if (type.id() == LogicalTypeId::STRUCT) { - child_list_t children; - children.reserve(StructType::GetChildCount(type)); - for (auto &child : StructType::GetChildTypes(type)) { - children.emplace_back(child.first, GetUserTypeRecursive(child.second, context)); - } - return LogicalType::STRUCT(children); - } - if (type.id() == LogicalTypeId::LIST) { - return LogicalType::LIST(GetUserTypeRecursive(ListType::GetChildType(type), context)); - } - if (type.id() == LogicalTypeId::ARRAY) { - return LogicalType::ARRAY(GetUserTypeRecursive(ArrayType::GetChildType(type), context), - ArrayType::GetSize(type)); - } - if (type.id() == LogicalTypeId::MAP) { - return LogicalType::MAP(GetUserTypeRecursive(MapType::KeyType(type), context), - GetUserTypeRecursive(MapType::ValueType(type), context)); - } - // Not LogicalTypeId::USER or a nested type - return type; -} - LogicalType TransformStringToLogicalType(const string &str, ClientContext &context) { - return GetUserTypeRecursive(TransformStringToLogicalType(str), context); + return TypeManager::Get(context).ParseLogicalType(str, context); } bool LogicalType::IsIntegral() const { @@ -1278,10 +1161,15 @@ struct ForceGetTypeOperation { bool LogicalType::TryGetMaxLogicalType(ClientContext &context, const LogicalType &left, const LogicalType &right, LogicalType &result) { - if (DBConfig::GetSetting(context)) { + if (Settings::Get(context)) { result = LogicalType::ForceMaxLogicalType(left, right); return true; } + return TryGetMaxLogicalTypeUnchecked(left, right, result); +} + +bool LogicalType::TryGetMaxLogicalTypeUnchecked(const LogicalType &left, const LogicalType &right, + LogicalType &result) { return TryGetMaxLogicalTypeInternal(left, right, result); } @@ -1378,7 +1266,8 @@ static idx_t GetLogicalTypeScore(const LogicalType &type) { case LogicalTypeId::AGGREGATE_STATE: case LogicalTypeId::POINTER: case LogicalTypeId::VALIDITY: - case LogicalTypeId::USER: + case LogicalTypeId::UNBOUND: + case LogicalTypeId::TYPE: break; } return 1000; @@ -1469,6 +1358,33 @@ bool ApproxEqual(double ldecimal, double rdecimal) { return std::fabs(ldecimal - rdecimal) <= epsilon; } +void LogicalType::Serialize(Serializer &serializer) const { + // This is a UNBOUND type and we are writing to older storage. + // 1. try to default-bind into a concrete logical type, and serialize that + // 2. if that fails, serialize normally, in which case the UNBOUND_TYPE_INFO will try to + // write itself as an old-style USER type. + if (id_ == LogicalTypeId::UNBOUND && !serializer.ShouldSerialize(7)) { + try { + auto bound_type = UnboundType::TryDefaultBind(*this); + if (bound_type.id() != LogicalTypeId::INVALID && bound_type.id() != LogicalTypeId::UNBOUND) { + bound_type.Serialize(serializer); + return; + } + } catch (...) { + // Ignore errors, just try to write as a USER type instead + } + } + serializer.WriteProperty(100, "id", id_); + serializer.WritePropertyWithDefault>(101, "type_info", type_info_); +} + +LogicalType LogicalType::Deserialize(Deserializer &deserializer) { + auto id = deserializer.ReadProperty(100, "id"); + auto type_info = deserializer.ReadPropertyWithDefault>(101, "type_info"); + LogicalType result(id, std::move(type_info)); + return result; +} + //===--------------------------------------------------------------------===// // Extra Type Info //===--------------------------------------------------------------------===// @@ -1499,9 +1415,6 @@ void LogicalType::SetAlias(string alias) { } string LogicalType::GetAlias() const { - if (id() == LogicalTypeId::USER) { - return UserType::GetTypeName(*this); - } if (type_info_) { return type_info_->alias; } @@ -1509,9 +1422,6 @@ string LogicalType::GetAlias() const { } bool LogicalType::HasAlias() const { - if (id() == LogicalTypeId::USER) { - return !UserType::GetTypeName(*this).empty(); - } if (type_info_ && !type_info_->alias.empty()) { return true; } @@ -1767,52 +1677,18 @@ const child_list_t UnionType::CopyMemberTypes(const LogicalType &ty } //===--------------------------------------------------------------------===// -// User Type +// Unbound Type //===--------------------------------------------------------------------===// -const string &UserType::GetCatalog(const LogicalType &type) { - D_ASSERT(type.id() == LogicalTypeId::USER); - auto info = type.AuxInfo(); - return info->Cast().catalog; -} - -const string &UserType::GetSchema(const LogicalType &type) { - D_ASSERT(type.id() == LogicalTypeId::USER); - auto info = type.AuxInfo(); - return info->Cast().schema; +LogicalType LogicalType::UNBOUND(unique_ptr expr) { + auto info = make_shared_ptr(std::move(expr)); + return LogicalType(LogicalTypeId::UNBOUND, std::move(info)); } -const string &UserType::GetTypeName(const LogicalType &type) { - D_ASSERT(type.id() == LogicalTypeId::USER); - auto info = type.AuxInfo(); - return info->Cast().user_type_name; -} - -const vector &UserType::GetTypeModifiers(const LogicalType &type) { - D_ASSERT(type.id() == LogicalTypeId::USER); - auto info = type.AuxInfo(); - return info->Cast().user_type_modifiers; -} - -vector &UserType::GetTypeModifiers(LogicalType &type) { - D_ASSERT(type.id() == LogicalTypeId::USER); - auto info = type.GetAuxInfoShrPtr(); - return info->Cast().user_type_modifiers; -} - -LogicalType LogicalType::USER(const string &user_type_name) { - auto info = make_shared_ptr(user_type_name); - return LogicalType(LogicalTypeId::USER, std::move(info)); -} - -LogicalType LogicalType::USER(const string &user_type_name, const vector &user_type_mods) { - auto info = make_shared_ptr(user_type_name, user_type_mods); - return LogicalType(LogicalTypeId::USER, std::move(info)); -} - -LogicalType LogicalType::USER(string catalog, string schema, string name, vector user_type_mods) { - auto info = make_shared_ptr(std::move(catalog), std::move(schema), std::move(name), - std::move(user_type_mods)); - return LogicalType(LogicalTypeId::USER, std::move(info)); +//===--------------------------------------------------------------------===// +// Type Type +//===--------------------------------------------------------------------===// +LogicalType LogicalType::TYPE() { + return LogicalType(LogicalTypeId::TYPE); } //===--------------------------------------------------------------------===// @@ -2079,6 +1955,77 @@ const CoordinateReferenceSystem &GeoType::GetCRS(const LogicalType &type) { return geo_info.crs; } +//===--------------------------------------------------------------------===// +// Unbound Types +//===--------------------------------------------------------------------===// + +const unique_ptr &UnboundType::GetTypeExpression(const LogicalType &type) { + D_ASSERT(type.id() == LogicalTypeId::UNBOUND); + auto info = type.AuxInfo(); + D_ASSERT(info->type == ExtraTypeInfoType::UNBOUND_TYPE_INFO); + return info->Cast().expr; +} + +LogicalType UnboundType::TryParseAndDefaultBind(const string &type_str) { + if (type_str.empty()) { + return LogicalType::INVALID; + } + try { + ColumnList list = Parser::ParseColumnList("dummy " + type_str); + auto unbound = list.GetColumn(LogicalIndex(0)).Type(); + return TryDefaultBind(unbound); + } catch (const std::runtime_error &e) { + throw InvalidInputException("Could not parse type string '%s'", type_str); + } +} + +static LogicalType TryDefaultBindTypeExpression(const ParsedExpression &expr) { + if (expr.type != ExpressionType::TYPE) { + throw InvalidInputException("Cannot default bind unbound type with non-type expression"); + } + const auto &type_expr = expr.Cast(); + + // Now we try to bind the unbound type to a default type + auto &name = type_expr.GetTypeName(); + auto &args = type_expr.GetChildren(); + + vector> bound_args; + for (auto &arg : args) { + switch (arg->GetExpressionType()) { + case ExpressionType::TYPE: { + auto type = TryDefaultBindTypeExpression(*arg); + bound_args.emplace_back(arg->GetName(), Value::TYPE(type)); + } break; + case ExpressionType::VALUE_CONSTANT: { + auto &const_expr = arg->Cast(); + bound_args.emplace_back(arg->GetName(), const_expr.value); + } break; + default: + throw InvalidInputException("Cannot default bind unbound type with non-type, non-expression parameter"); + break; + } + } + + // Try to bind as far as we can + auto result = DefaultTypeGenerator::TryDefaultBind(name, bound_args); + if (result.id() != LogicalTypeId::INVALID) { + return result; + } + + // Otherwise, wrap this as an unbound type + auto copy = expr.Copy(); + return LogicalType::UNBOUND(std::move(copy)); + // return LogicalType::INVALID; +} + +LogicalType UnboundType::TryDefaultBind(const LogicalType &unbound_type) { + if (!unbound_type.IsUnbound()) { + return unbound_type; + } + auto &expr = UnboundType::GetTypeExpression(unbound_type); + return TryDefaultBindTypeExpression(*expr); +} + //===--------------------------------------------------------------------===// // Logical Type //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/common/types/column/column_data_allocator.cpp b/src/duckdb/src/common/types/column/column_data_allocator.cpp index b0fefb32e..235fe766f 100644 --- a/src/duckdb/src/common/types/column/column_data_allocator.cpp +++ b/src/duckdb/src/common/types/column/column_data_allocator.cpp @@ -72,7 +72,7 @@ ColumnDataAllocator::~ColumnDataAllocator() { return; } for (auto &block : blocks) { - block.GetHandle()->SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); + block.GetHandle()->GetMemory().SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); } blocks.clear(); } @@ -101,7 +101,8 @@ BufferHandle ColumnDataAllocator::AllocateBlock(idx_t size) { data.SetHandle(managed_result_set, pin.GetBlockHandle()); blocks.push_back(std::move(data)); if (partition_index.IsValid()) { // Set the eviction queue index logarithmically using RadixBits - blocks.back().GetHandle()->SetEvictionQueueIndex(RadixPartitioning::RadixBits(partition_index.GetIndex())); + blocks.back().GetHandle()->GetMemory().SetEvictionQueueIndex( + RadixPartitioning::RadixBits(partition_index.GetIndex())); } allocated_size += max_size; return pin; @@ -255,7 +256,7 @@ void ColumnDataAllocator::UnswizzlePointers(ChunkManagementState &state, Vector } void ColumnDataAllocator::SetDestroyBufferUponUnpin(uint32_t block_id) { - blocks[block_id].GetHandle()->SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); + blocks[block_id].GetHandle()->GetMemory().SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); } shared_ptr ColumnDataAllocator::GetDatabase() const { diff --git a/src/duckdb/src/common/types/column/column_data_collection.cpp b/src/duckdb/src/common/types/column/column_data_collection.cpp index d9d69b151..640c283c1 100644 --- a/src/duckdb/src/common/types/column/column_data_collection.cpp +++ b/src/duckdb/src/common/types/column/column_data_collection.cpp @@ -213,8 +213,8 @@ ColumnDataChunkIterationHelper::ColumnDataChunkIterationHelper(const ColumnDataC } ColumnDataChunkIterationHelper::ColumnDataChunkIterator::ColumnDataChunkIterator( - const ColumnDataCollection *collection_p, vector column_ids_p) - : collection(collection_p), scan_chunk(make_shared_ptr()), row_index(0) { + optional_ptr collection_p, vector column_ids_p) + : collection(collection_p), scan_chunk(make_uniq()), row_index(0) { if (!collection) { return; } @@ -223,6 +223,15 @@ ColumnDataChunkIterationHelper::ColumnDataChunkIterator::ColumnDataChunkIterator collection->Scan(scan_state, *scan_chunk); } +ColumnDataChunkIterationHelper::ColumnDataChunkIterator::ColumnDataChunkIterator( + ColumnDataChunkIterator &&other) noexcept + : row_index(0) { + std::swap(collection, other.collection); + std::swap(scan_state, other.scan_state); + std::swap(scan_chunk, other.scan_chunk); + std::swap(row_index, other.row_index); +} + void ColumnDataChunkIterationHelper::ColumnDataChunkIterator::Next() { if (!collection) { return; diff --git a/src/duckdb/src/common/types/geometry.cpp b/src/duckdb/src/common/types/geometry.cpp index cc9bacfda..52c17c405 100644 --- a/src/duckdb/src/common/types/geometry.cpp +++ b/src/duckdb/src/common/types/geometry.cpp @@ -929,7 +929,6 @@ void ConvertWKB(BlobReader &reader, FixedSizeBlobWriter &writer) { // Public interface //---------------------------------------------------------------------------------------------------------------------- namespace duckdb { - constexpr const idx_t Geometry::MAX_RECURSION_DEPTH; bool Geometry::FromBinary(const string_t &wkb, string_t &result, Vector &result_vector, bool strict) { @@ -1083,6 +1082,11 @@ static uint32_t ParseVertices(BlobReader &reader, GeometryExtent &extent, uint32 } uint32_t Geometry::GetExtent(const string_t &wkb, GeometryExtent &extent) { + bool has_any_empty = false; + return GetExtent(wkb, extent, has_any_empty); +} + +uint32_t Geometry::GetExtent(const string_t &wkb, GeometryExtent &extent, bool &has_any_empty) { BlobReader reader(wkb.GetData(), static_cast(wkb.GetSize())); uint32_t vertex_count = 0; @@ -1106,16 +1110,33 @@ uint32_t Geometry::GetExtent(const string_t &wkb, GeometryExtent &extent) { switch (geom_type) { case GeometryType::POINT: { - vertex_count += ParseVertices(reader, extent, 1, vert_type, true); + const auto parsed_count = ParseVertices(reader, extent, 1, vert_type, true); + if (parsed_count == 0) { + has_any_empty = true; + continue; + } + vertex_count += parsed_count; } break; case GeometryType::LINESTRING: { const auto vert_count = reader.Read(); + if (vert_count == 0) { + has_any_empty = true; + continue; + } vertex_count += ParseVertices(reader, extent, vert_count, vert_type, false); } break; case GeometryType::POLYGON: { const auto ring_count = reader.Read(); + if (ring_count == 0) { + has_any_empty = true; + continue; + } for (uint32_t ring_idx = 0; ring_idx < ring_count; ring_idx++) { const auto vert_count = reader.Read(); + if (vert_count == 0) { + has_any_empty = true; + continue; + } vertex_count += ParseVertices(reader, extent, vert_count, vert_type, false); } } break; @@ -1123,8 +1144,10 @@ uint32_t Geometry::GetExtent(const string_t &wkb, GeometryExtent &extent) { case GeometryType::MULTILINESTRING: case GeometryType::MULTIPOLYGON: case GeometryType::GEOMETRYCOLLECTION: { - // Skip count. We don't need it for extent calculation. - reader.Skip(sizeof(uint32_t)); + const auto part_count = reader.Read(); + if (part_count == 0) { + has_any_empty = true; + } } break; default: throw InvalidInputException("Unsupported geometry type %d in WKB", static_cast(geom_type)); @@ -1133,4 +1156,1039 @@ uint32_t Geometry::GetExtent(const string_t &wkb, GeometryExtent &extent) { return vertex_count; } +//---------------------------------------------------------------------------------------------------------------------- +// Shredding +//---------------------------------------------------------------------------------------------------------------------- + +template +static void ToPoints(Vector &source_vec, Vector &target_vec, idx_t row_count) { + // Flatten the source vector to extract all vertices + source_vec.Flatten(row_count); + + const auto geom_data = FlatVector::GetData(source_vec); + const auto &vert_parts = StructVector::GetEntries(target_vec); + double *vert_data[V::WIDTH]; + + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, row_idx, true); + continue; + } + + const auto &blob = geom_data[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + vert_data[dim_idx][row_idx] = reader.Read(); + } + } +} + +template +static void FromPoints(Vector &source_vec, Vector &target_vec, idx_t row_count, idx_t result_offset) { + // Flatten the source vector to extract all vertices + source_vec.Flatten(row_count); + + const auto &vert_parts = StructVector::GetEntries(source_vec); + const auto geom_data = FlatVector::GetData(target_vec); + double *vert_data[V::WIDTH]; + + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + const auto out_idx = result_offset + row_idx; + + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, out_idx, true); + continue; + } + + // byte order + type/meta + vertex data + const auto blob_size = sizeof(uint8_t) + sizeof(uint32_t) + sizeof(V); + auto blob = StringVector::EmptyString(target_vec, blob_size); + const auto blob_data = blob.GetDataWriteable(); + + FixedSizeBlobWriter writer(blob_data, static_cast(blob_size)); + + const auto meta = static_cast(GeometryType::POINT) + (V::HAS_Z ? 1000 : 0) + (V::HAS_M ? 2000 : 0); + + writer.Write(1); // Little-endian + writer.Write(meta); // Type/meta + + // Write vertex data + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + writer.Write(vert_data[dim_idx][row_idx]); + } + + blob.Finalize(); + geom_data[out_idx] = blob; + } +} + +template +static void ToLineStrings(Vector &source_vec, Vector &target_vec, idx_t row_count) { + // Flatten the source vector to extract all vertices + source_vec.Flatten(row_count); + + idx_t vert_total = 0; + idx_t vert_start = 0; + + // First pass, figure out how many vertices are in this linestring + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, row_idx, true); + continue; + } + + const auto &blob = FlatVector::GetData(source_vec)[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + const auto vert_count = reader.Read(); + + vert_total += vert_count; + } + + ListVector::Reserve(target_vec, vert_total); + ListVector::SetListSize(target_vec, vert_total); + + auto list_data = ListVector::GetData(target_vec); + auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(target_vec)); + double *vert_data[V::WIDTH]; + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + // Second pass, write out the linestrings + + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + continue; + } + + const auto &blob = FlatVector::GetData(source_vec)[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + const auto vert_count = reader.Read(); + + // Set list entry + auto &list_entry = list_data[row_idx]; + list_entry.offset = vert_start; + list_entry.length = vert_count; + + // Read vertices + for (uint32_t vert_idx = 0; vert_idx < vert_count; vert_idx++) { + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + vert_data[dim_idx][vert_start + vert_idx] = reader.Read(); + } + } + + vert_start += vert_count; + } + + D_ASSERT(vert_start == vert_total); +} + +template +static void FromLineStrings(Vector &source_vec, Vector &target_vec, idx_t row_count, idx_t result_offset) { + // Flatten the source vector to extract all vertices + source_vec.Flatten(row_count); + + const auto line_data = ListVector::GetData(source_vec); + const auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(source_vec)); + + double *vert_data[V::WIDTH]; + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + const auto out_idx = result_offset + row_idx; + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, out_idx, true); + continue; + } + + const auto &line_entry = line_data[row_idx]; + const auto vert_count = line_entry.length; + + // byte order + type/meta + vertex data + const auto blob_size = sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t) + vert_count * sizeof(V); + auto blob = StringVector::EmptyString(target_vec, blob_size); + const auto blob_data = blob.GetDataWriteable(); + + FixedSizeBlobWriter writer(blob_data, static_cast(blob_size)); + + const auto meta = + static_cast(GeometryType::LINESTRING) + (V::HAS_Z ? 1000 : 0) + (V::HAS_M ? 2000 : 0); + + writer.Write(1); // Little-endian + writer.Write(meta); // Type/meta + writer.Write(UnsafeNumericCast(vert_count)); // Vertex count + + // Write vertex data + for (uint32_t vert_idx = 0; vert_idx < vert_count; vert_idx++) { + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + writer.Write(vert_data[dim_idx][line_entry.offset + vert_idx]); + } + } + + blob.Finalize(); + FlatVector::GetData(target_vec)[out_idx] = blob; + } +} + +template +static void ToPolygons(Vector &source_vec, Vector &target_vec, idx_t row_count) { + source_vec.Flatten(row_count); + + idx_t vert_total = 0; + idx_t ring_total = 0; + idx_t vert_start = 0; + idx_t ring_start = 0; + + // First pass, figure out how many vertices and rings are in this polygon + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, row_idx, true); + continue; + } + + const auto &blob = FlatVector::GetData(source_vec)[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + const auto ring_count = reader.Read(); + for (uint32_t ring_idx = 0; ring_idx < ring_count; ring_idx++) { + const auto vert_count = reader.Read(); + + // Skip vertices + reader.Skip(sizeof(V) * vert_count); + + vert_total += vert_count; + } + ring_total += ring_count; + } + + // Reserve space in the target vector + ListVector::Reserve(target_vec, ring_total); + ListVector::SetListSize(target_vec, ring_total); + + auto &ring_vec = ListVector::GetEntry(target_vec); + ListVector::Reserve(ring_vec, vert_total); + ListVector::SetListSize(ring_vec, vert_total); + + const auto poly_data = ListVector::GetData(target_vec); + const auto ring_data = ListVector::GetData(ring_vec); + auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(ring_vec)); + double *vert_data[V::WIDTH]; + + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + continue; + } + + const auto &blob = FlatVector::GetData(source_vec)[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + const auto ring_count = reader.Read(); + // Set polygon entry + auto &poly_entry = poly_data[row_idx]; + poly_entry.offset = ring_start; + poly_entry.length = ring_count; + + for (uint32_t ring_idx = 0; ring_idx < ring_count; ring_idx++) { + const auto vert_count = reader.Read(); + + // Set ring entry + auto &ring_entry = ring_data[ring_start + ring_idx]; + ring_entry.offset = vert_start; + ring_entry.length = vert_count; + + // Read vertices + for (uint32_t vert_idx = 0; vert_idx < vert_count; vert_idx++) { + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + vert_data[dim_idx][vert_start + vert_idx] = reader.Read(); + } + } + + vert_start += vert_count; + } + + ring_start += ring_count; + } + + D_ASSERT(vert_start == vert_total); + D_ASSERT(ring_start == ring_total); +} + +template +static void FromPolygons(Vector &source_vec, Vector &target_vec, idx_t row_count, idx_t result_offset) { + source_vec.Flatten(row_count); + + const auto poly_data = ListVector::GetData(source_vec); + const auto &ring_vec = ListVector::GetEntry(source_vec); + const auto ring_data = ListVector::GetData(ring_vec); + const auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(ring_vec)); + + double *vert_data[V::WIDTH]; + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + const auto out_idx = result_offset + row_idx; + + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, out_idx, true); + continue; + } + + const auto &poly_entry = poly_data[row_idx]; + const auto ring_count = poly_entry.length; + + // First, compute total size + idx_t blob_size = sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t); // byte order + type/meta + ring count + + for (uint32_t ring_idx = 0; ring_idx < ring_count; ring_idx++) { + const auto &ring_entry = ring_data[poly_entry.offset + ring_idx]; + const auto vert_count = ring_entry.length; + // vertex count + blob_size += sizeof(uint32_t); + // vertex data + blob_size += vert_count * sizeof(V); + } + + auto blob = StringVector::EmptyString(target_vec, blob_size); + const auto blob_data = blob.GetDataWriteable(); + + FixedSizeBlobWriter writer(blob_data, static_cast(blob_size)); + + const auto meta = static_cast(GeometryType::POLYGON) + (V::HAS_Z ? 1000 : 0) + (V::HAS_M ? 2000 : 0); + + writer.Write(1); // Little-endian + writer.Write(meta); // Type/meta + writer.Write(UnsafeNumericCast(ring_count)); // Ring count + + for (uint32_t ring_idx = 0; ring_idx < ring_count; ring_idx++) { + const auto &ring_entry = ring_data[poly_entry.offset + ring_idx]; + const auto vert_count = ring_entry.length; + + writer.Write(UnsafeNumericCast(vert_count)); // Vertex count + + // Write vertex data + for (uint32_t vert_idx = 0; vert_idx < vert_count; vert_idx++) { + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + writer.Write(vert_data[dim_idx][ring_entry.offset + vert_idx]); + } + } + } + + blob.Finalize(); + FlatVector::GetData(target_vec)[out_idx] = blob; + } +} + +template +static void ToMultiPoints(Vector &source_vec, Vector &target_vec, idx_t row_count) { + source_vec.Flatten(row_count); + + const auto geom_data = FlatVector::GetData(source_vec); + + idx_t vert_total = 0; + idx_t vert_start = 0; + + // First pass, figure out how many vertices are in this multipoint + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, row_idx, true); + continue; + } + const auto &blob = geom_data[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + const auto part_count = reader.Read(); + vert_total += part_count; + } + + // Reserve space in the target vector + ListVector::Reserve(target_vec, vert_total); + ListVector::SetListSize(target_vec, vert_total); + + auto mult_data = ListVector::GetData(target_vec); + auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(target_vec)); + double *vert_data[V::WIDTH]; + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + // Second pass, write out the multipoints + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + continue; + } + + const auto &blob = geom_data[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + const auto part_count = reader.Read(); + + // Set multipoint entry + auto &mult_entry = mult_data[row_idx]; + mult_entry.offset = vert_start; + mult_entry.length = part_count; + + for (uint32_t part_idx = 0; part_idx < part_count; part_idx++) { + // Skip byte order and type/meta of the point + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + vert_data[dim_idx][vert_start + part_idx] = reader.Read(); + } + } + + vert_start += part_count; + } + + D_ASSERT(vert_start == vert_total); +} + +template +static void FromMultiPoints(Vector &source_vec, Vector &target_vec, idx_t row_count, idx_t result_offset) { + // Flatten the source vector to extract all vertices + source_vec.Flatten(row_count); + + const auto mult_data = ListVector::GetData(source_vec); + const auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(source_vec)); + + double *vert_data[V::WIDTH]; + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + const auto out_idx = result_offset + row_idx; + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, out_idx, true); + continue; + } + + const auto &mult_entry = mult_data[row_idx]; + const auto part_count = mult_entry.length; + + // First, compute total size + // byte order + type/meta + part count + idx_t blob_size = sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t); + + for (uint32_t part_idx = 0; part_idx < part_count; part_idx++) { + // point byte order + type/meta + vertex data + blob_size += sizeof(uint8_t) + sizeof(uint32_t) + sizeof(V); + } + + auto blob = StringVector::EmptyString(target_vec, blob_size); + const auto blob_data = blob.GetDataWriteable(); + + FixedSizeBlobWriter writer(blob_data, static_cast(blob_size)); + + const auto meta = + static_cast(GeometryType::MULTIPOINT) + (V::HAS_Z ? 1000 : 0) + (V::HAS_M ? 2000 : 0); + + writer.Write(1); // Little-endian + writer.Write(meta); // Type/meta + writer.Write(UnsafeNumericCast(part_count)); // Part count + + for (uint32_t part_idx = 0; part_idx < part_count; part_idx++) { + // Write point byte order and type/meta + const auto point_meta = + static_cast(GeometryType::POINT) + (V::HAS_Z ? 1000 : 0) + (V::HAS_M ? 2000 : 0); + writer.Write(1); // Little-endian + writer.Write(point_meta); // Type/meta + + // Write vertex data + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + writer.Write(vert_data[dim_idx][mult_entry.offset + part_idx]); + } + } + + blob.Finalize(); + FlatVector::GetData(target_vec)[out_idx] = blob; + } +} + +template +static void ToMultiLineStrings(Vector &source_vec, Vector &target_vec, idx_t row_count) { + // Flatten the source vector to extract all vertices + source_vec.Flatten(row_count); + + // This is basically the same as Polygons + + idx_t vert_total = 0; + idx_t line_total = 0; + idx_t vert_start = 0; + idx_t line_start = 0; + + // First pass, figure out how many vertices and lines are in this multilinestring + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, row_idx, true); + continue; + } + + const auto &blob = FlatVector::GetData(source_vec)[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + // Line count + const auto line_count = reader.Read(); + for (uint32_t line_idx = 0; line_idx < line_count; line_idx++) { + // Skip line metadata + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + // Read vertex count + const auto vert_count = reader.Read(); + // Skip vertices + reader.Skip(sizeof(V) * vert_count); + + vert_total += vert_count; + } + line_total += line_count; + } + + // Reserve space in the target vector + ListVector::Reserve(target_vec, line_total); + ListVector::SetListSize(target_vec, line_total); + + auto &line_vec = ListVector::GetEntry(target_vec); + ListVector::Reserve(line_vec, vert_total); + ListVector::SetListSize(line_vec, vert_total); + + const auto mult_data = ListVector::GetData(target_vec); + const auto line_data = ListVector::GetData(line_vec); + auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(line_vec)); + double *vert_data[V::WIDTH]; + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + // Second pass, write out the multilinestrings + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + continue; + } + const auto &blob = FlatVector::GetData(source_vec)[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + const auto line_count = reader.Read(); + + // Set multilinestring entry + auto &mult_entry = mult_data[row_idx]; + mult_entry.offset = line_start; + mult_entry.length = line_count; + + for (uint32_t line_idx = 0; line_idx < line_count; line_idx++) { + // Skip line byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + // Read vertex count + const auto vert_count = reader.Read(); + + // Set line entry + auto &line_entry = line_data[line_start + line_idx]; + line_entry.offset = vert_start; + line_entry.length = vert_count; + + // Read vertices + for (uint32_t vert_idx = 0; vert_idx < vert_count; vert_idx++) { + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + vert_data[dim_idx][vert_start + vert_idx] = reader.Read(); + } + } + + vert_start += vert_count; + } + line_start += line_count; + } + + D_ASSERT(vert_start == vert_total); + D_ASSERT(line_start == line_total); +} + +template +static void FromMultiLineStrings(Vector &source_vec, Vector &target_vec, idx_t row_count, idx_t result_offset) { + // Flatten the source vector to extract all vertices + + source_vec.Flatten(row_count); + + const auto mult_data = ListVector::GetData(source_vec); + const auto line_vec = ListVector::GetEntry(source_vec); + const auto line_data = ListVector::GetData(line_vec); + const auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(line_vec)); + double *vert_data[V::WIDTH]; + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + const auto out_idx = result_offset + row_idx; + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, out_idx, true); + continue; + } + + const auto &mult_entry = mult_data[row_idx]; + const auto line_count = mult_entry.length; + + // First, compute total size + // byte order + type/meta + line count + idx_t blob_size = sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t); + + for (uint32_t line_idx = 0; line_idx < line_count; line_idx++) { + const auto &line_entry = line_data[mult_entry.offset + line_idx]; + const auto vert_count = line_entry.length; + // line byte order + type/meta + vertex count + blob_size += sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t); + // vertex data + blob_size += vert_count * sizeof(V); + } + + auto blob = StringVector::EmptyString(target_vec, blob_size); + const auto blob_data = blob.GetDataWriteable(); + + FixedSizeBlobWriter writer(blob_data, static_cast(blob_size)); + + const auto meta = + static_cast(GeometryType::MULTILINESTRING) + (V::HAS_Z ? 1000 : 0) + (V::HAS_M ? 2000 : 0); + + writer.Write(1); // Little-endian + writer.Write(meta); // Type/meta + writer.Write(UnsafeNumericCast(line_count)); // Line count + + for (uint32_t line_idx = 0; line_idx < line_count; line_idx++) { + const auto &line_entry = line_data[mult_entry.offset + line_idx]; + const auto vert_count = line_entry.length; + + // Write line byte order and type/meta + const auto line_meta = + static_cast(GeometryType::LINESTRING) + (V::HAS_Z ? 1000 : 0) + (V::HAS_M ? 2000 : 0); + writer.Write(1); // Little-endian + writer.Write(line_meta); // Type/meta + writer.Write(UnsafeNumericCast(vert_count)); // Vertex count + + // Write vertex data + for (uint32_t vert_idx = 0; vert_idx < vert_count; vert_idx++) { + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + writer.Write(vert_data[dim_idx][line_entry.offset + vert_idx]); + } + } + } + blob.Finalize(); + FlatVector::GetData(target_vec)[out_idx] = blob; + } +} + +template +static void ToMultiPolygons(Vector &source_vec, Vector &target_vec, idx_t row_count) { + // Flatten the source vector to extract all vertices + source_vec.Flatten(row_count); + + idx_t vert_total = 0; + idx_t ring_total = 0; + idx_t poly_total = 0; + idx_t vert_start = 0; + idx_t ring_start = 0; + idx_t poly_start = 0; + + // First pass, figure out how many vertices, rings and polygons are in this multipolygon + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, row_idx, true); + continue; + } + + const auto &blob = FlatVector::GetData(source_vec)[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + BlobReader reader(blob_data, static_cast(blob_size)); + + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + const auto poly_count = reader.Read(); + for (uint32_t poly_idx = 0; poly_idx < poly_count; poly_idx++) { + // Skip polygon byte order and metadata + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + // Read ring count + const auto ring_count = reader.Read(); + for (uint32_t ring_idx = 0; ring_idx < ring_count; ring_idx++) { + // Read vertex count + const auto vert_count = reader.Read(); + // Skip vertices + reader.Skip(sizeof(V) * vert_count); + + vert_total += vert_count; + } + ring_total += ring_count; + } + poly_total += poly_count; + } + + // Reserve space in the target vector + ListVector::Reserve(target_vec, poly_total); + ListVector::SetListSize(target_vec, poly_total); + auto &poly_vec = ListVector::GetEntry(target_vec); + ListVector::Reserve(poly_vec, ring_total); + ListVector::SetListSize(poly_vec, ring_total); + auto &ring_vec = ListVector::GetEntry(poly_vec); + ListVector::Reserve(ring_vec, vert_total); + ListVector::SetListSize(ring_vec, vert_total); + + const auto mult_data = ListVector::GetData(target_vec); + const auto poly_data = ListVector::GetData(poly_vec); + const auto ring_data = ListVector::GetData(ring_vec); + auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(ring_vec)); + double *vert_data[V::WIDTH]; + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + // Second pass, write out the multipolygons + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + if (FlatVector::IsNull(source_vec, row_idx)) { + continue; + } + const auto &blob = FlatVector::GetData(source_vec)[row_idx]; + const auto blob_data = blob.GetData(); + const auto blob_size = blob.GetSize(); + + BlobReader reader(blob_data, static_cast(blob_size)); + + // Skip byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + const auto poly_count = reader.Read(); + + // Set multipolygon entry + auto &mult_entry = mult_data[row_idx]; + mult_entry.offset = poly_start; + mult_entry.length = poly_count; + + // Read polygons + for (uint32_t poly_idx = 0; poly_idx < poly_count; poly_idx++) { + // Skip polygon byte order and type/meta + reader.Skip(sizeof(uint8_t) + sizeof(uint32_t)); + + // Read ring count + const auto ring_count = reader.Read(); + + // Set polygon entry + auto &poly_entry = poly_data[poly_start + poly_idx]; + poly_entry.offset = ring_start; + poly_entry.length = ring_count; + + // Read rings + for (uint32_t ring_idx = 0; ring_idx < ring_count; ring_idx++) { + // Read vertex count + const auto vert_count = reader.Read(); + // Set ring entry + auto &ring_entry = ring_data[ring_start + ring_idx]; + ring_entry.offset = vert_start; + ring_entry.length = vert_count; + + // Read vertices + for (uint32_t vert_idx = 0; vert_idx < vert_count; vert_idx++) { + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + vert_data[dim_idx][vert_start + vert_idx] = reader.Read(); + } + } + vert_start += vert_count; + } + ring_start += ring_count; + } + poly_start += poly_count; + } +} + +template +static void FromMultiPolygons(Vector &source_vec, Vector &target_vec, idx_t row_count, idx_t result_offset) { + // Flatten the source vector to extract all vertices + source_vec.Flatten(row_count); + + const auto mult_data = ListVector::GetData(source_vec); + const auto &poly_vec = ListVector::GetEntry(source_vec); + const auto poly_data = ListVector::GetData(poly_vec); + const auto &ring_vec = ListVector::GetEntry(poly_vec); + const auto ring_data = ListVector::GetData(ring_vec); + const auto &vert_parts = StructVector::GetEntries(ListVector::GetEntry(ring_vec)); + double *vert_data[V::WIDTH]; + for (idx_t i = 0; i < V::WIDTH; i++) { + vert_data[i] = FlatVector::GetData(*vert_parts[i]); + } + + for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { + const auto out_idx = result_offset + row_idx; + if (FlatVector::IsNull(source_vec, row_idx)) { + FlatVector::SetNull(target_vec, out_idx, true); + continue; + } + + const auto &mult_entry = mult_data[row_idx]; + const auto poly_count = mult_entry.length; + + // First, compute total size + // byte order + type/meta + polygon count + idx_t blob_size = sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t); + + for (uint32_t poly_idx = 0; poly_idx < poly_count; poly_idx++) { + const auto &poly_entry = poly_data[mult_entry.offset + poly_idx]; + const auto ring_count = poly_entry.length; + // polygon byte order + type/meta + ring count + blob_size += sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t); + + for (uint32_t ring_idx = 0; ring_idx < ring_count; ring_idx++) { + const auto &ring_entry = ring_data[poly_entry.offset + ring_idx]; + const auto vert_count = ring_entry.length; + // vertex count + blob_size += sizeof(uint32_t); + // vertex data + blob_size += vert_count * sizeof(V); + } + } + + auto blob = StringVector::EmptyString(target_vec, blob_size); + const auto blob_data = blob.GetDataWriteable(); + + FixedSizeBlobWriter writer(blob_data, static_cast(blob_size)); + + const auto meta = + static_cast(GeometryType::MULTIPOLYGON) + (V::HAS_Z ? 1000 : 0) + (V::HAS_M ? 2000 : 0); + writer.Write(1); // Little-endian + writer.Write(meta); // Type/meta + writer.Write(UnsafeNumericCast(poly_count)); // Polygon count + + for (uint32_t poly_idx = 0; poly_idx < poly_count; poly_idx++) { + const auto &poly_entry = poly_data[mult_entry.offset + poly_idx]; + const auto ring_count = poly_entry.length; + + // Write polygon byte order and type/meta + const auto poly_meta = + static_cast(GeometryType::POLYGON) + (V::HAS_Z ? 1000 : 0) + (V::HAS_M ? 2000 : 0); + writer.Write(1); // Little-endian + writer.Write(poly_meta); // Type/meta + writer.Write(UnsafeNumericCast(ring_count)); // Ring count + + for (uint32_t ring_idx = 0; ring_idx < ring_count; ring_idx++) { + const auto &ring_entry = ring_data[poly_entry.offset + ring_idx]; + const auto vert_count = ring_entry.length; + + writer.Write(UnsafeNumericCast(vert_count)); // Vertex count + + // Write vertex data + for (uint32_t vert_idx = 0; vert_idx < vert_count; vert_idx++) { + for (uint32_t dim_idx = 0; dim_idx < V::WIDTH; dim_idx++) { + writer.Write(vert_data[dim_idx][ring_entry.offset + vert_idx]); + } + } + } + } + + blob.Finalize(); + FlatVector::GetData(target_vec)[out_idx] = blob; + } +} + +template +static void ToVectorizedFormatInternal(Vector &source, Vector &target, idx_t count, GeometryType geom_type) { + switch (geom_type) { + case GeometryType::POINT: + ToPoints(source, target, count); + break; + case GeometryType::LINESTRING: + ToLineStrings(source, target, count); + break; + case GeometryType::POLYGON: + ToPolygons(source, target, count); + break; + case GeometryType::MULTIPOINT: + ToMultiPoints(source, target, count); + break; + case GeometryType::MULTILINESTRING: + ToMultiLineStrings(source, target, count); + break; + case GeometryType::MULTIPOLYGON: + ToMultiPolygons(source, target, count); + break; + default: + throw NotImplementedException("Unsupported geometry type %d", static_cast(geom_type)); + } +} + +void Geometry::ToVectorizedFormat(Vector &source, Vector &target, idx_t count, GeometryType geom_type, + VertexType vert_type) { + switch (vert_type) { + case VertexType::XY: + ToVectorizedFormatInternal(source, target, count, geom_type); + break; + case VertexType::XYZ: + ToVectorizedFormatInternal(source, target, count, geom_type); + break; + case VertexType::XYM: + ToVectorizedFormatInternal(source, target, count, geom_type); + break; + case VertexType::XYZM: + ToVectorizedFormatInternal(source, target, count, geom_type); + break; + default: + throw InvalidInputException("Unsupported vertex type %d", static_cast(vert_type)); + } +} + +template +static void FromVectorizedFormatInternal(Vector &source, Vector &target, idx_t count, GeometryType geom_type, + idx_t result_offset) { + switch (geom_type) { + case GeometryType::POINT: + FromPoints(source, target, count, result_offset); + break; + case GeometryType::LINESTRING: + FromLineStrings(source, target, count, result_offset); + break; + case GeometryType::POLYGON: + FromPolygons(source, target, count, result_offset); + break; + case GeometryType::MULTIPOINT: + FromMultiPoints(source, target, count, result_offset); + break; + case GeometryType::MULTILINESTRING: + FromMultiLineStrings(source, target, count, result_offset); + break; + case GeometryType::MULTIPOLYGON: + FromMultiPolygons(source, target, count, result_offset); + break; + default: + throw NotImplementedException("Unsupported geometry type %d", static_cast(geom_type)); + } +} + +void Geometry::FromVectorizedFormat(Vector &source, Vector &target, idx_t count, GeometryType geom_type, + VertexType vert_type, idx_t result_offset) { + switch (vert_type) { + case VertexType::XY: + FromVectorizedFormatInternal(source, target, count, geom_type, result_offset); + break; + case VertexType::XYZ: + FromVectorizedFormatInternal(source, target, count, geom_type, result_offset); + break; + case VertexType::XYM: + FromVectorizedFormatInternal(source, target, count, geom_type, result_offset); + break; + case VertexType::XYZM: + FromVectorizedFormatInternal(source, target, count, geom_type, result_offset); + break; + default: + throw InvalidInputException("Unsupported vertex type %d", static_cast(vert_type)); + } +} + +static LogicalType GetVectorizedTypeInternal(GeometryType geom_type, LogicalType vertex_type) { + switch (geom_type) { + case GeometryType::POINT: + return vertex_type; + case GeometryType::LINESTRING: + return LogicalType::LIST(vertex_type); + case GeometryType::POLYGON: + return LogicalType::LIST(LogicalType::LIST(vertex_type)); + case GeometryType::MULTIPOINT: + return LogicalType::LIST(vertex_type); + case GeometryType::MULTILINESTRING: + return LogicalType::LIST(LogicalType::LIST(vertex_type)); + case GeometryType::MULTIPOLYGON: + return LogicalType::LIST(LogicalType::LIST(LogicalType::LIST(vertex_type))); + case GeometryType::GEOMETRYCOLLECTION: + throw NotImplementedException("GEOMETRYCOLLECTION vectorized type not implemented"); + default: + throw InvalidInputException("Unsupported geometry type %d", static_cast(geom_type)); + } +} + +LogicalType Geometry::GetVectorizedType(GeometryType geom_type, VertexType vert_type) { + switch (vert_type) { + case VertexType::XY: { + auto vert = LogicalType::STRUCT({{"x", LogicalType::DOUBLE}, {"y", LogicalType::DOUBLE}}); + return GetVectorizedTypeInternal(geom_type, std::move(vert)); + } + case VertexType::XYZ: { + auto vert = + LogicalType::STRUCT({{"x", LogicalType::DOUBLE}, {"y", LogicalType::DOUBLE}, {"z", LogicalType::DOUBLE}}); + return GetVectorizedTypeInternal(geom_type, std::move(vert)); + } + case VertexType::XYM: { + auto vert = + LogicalType::STRUCT({{"x", LogicalType::DOUBLE}, {"y", LogicalType::DOUBLE}, {"m", LogicalType::DOUBLE}}); + return GetVectorizedTypeInternal(geom_type, std::move(vert)); + } + case VertexType::XYZM: { + auto vert = LogicalType::STRUCT({{"x", LogicalType::DOUBLE}, + {"y", LogicalType::DOUBLE}, + {"z", LogicalType::DOUBLE}, + {"m", LogicalType::DOUBLE}}); + return GetVectorizedTypeInternal(geom_type, std::move(vert)); + } + default: + throw InvalidInputException("Unsupported vertex type %d", static_cast(vert_type)); + } +} + } // namespace duckdb diff --git a/src/duckdb/src/common/types/geometry_crs.cpp b/src/duckdb/src/common/types/geometry_crs.cpp index ddff6038f..9e0bf3e54 100644 --- a/src/duckdb/src/common/types/geometry_crs.cpp +++ b/src/duckdb/src/common/types/geometry_crs.cpp @@ -1,91 +1,24 @@ #include "duckdb/common/types/geometry_crs.hpp" - #include "duckdb/common/common.hpp" +#include "duckdb/main/extension_callback_manager.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" +#include "duckdb/common/array.hpp" +#include "duckdb/common/helper.hpp" #include "yyjson.hpp" +#include "duckdb/catalog/catalog_entry/coordinate_system_catalog_entry.hpp" #include "fast_float/fast_float.h" #include -#include -#include namespace duckdb { -void CoordinateReferenceSystem::Parse(const string &text, CoordinateReferenceSystem &result) { - if (text.empty()) { - result.type = CoordinateReferenceSystemType::INVALID; - return; - } - - // Check if the text is all whitespace - auto all_space = true; - for (const auto c : text) { - if (!StringUtil::CharacterIsSpace(c)) { - all_space = false; - break; - } - } - - if (all_space) { - result.type = CoordinateReferenceSystemType::INVALID; - return; - } - - if (TryParsePROJJSON(text, result)) { - return; - } - - if (TryParseAuthCode(text, result)) { - return; - } - - // TODO: Also strip formatting - if (TryParseWKT2(text, result)) { - return; - } - - // Otherwise, treat this as an opaque SRID identifier, and don't set an explicit name or id - result.type = CoordinateReferenceSystemType::SRID; - result.text = text; -} - -bool CoordinateReferenceSystem::TryParse(const string &text, CoordinateReferenceSystem &result) { - try { - Parse(text, result); - } catch (const InvalidInputException &ex) { - return false; - } - return true; -} - -CoordinateReferenceSystem::CoordinateReferenceSystem(const string &crs) { - Parse(crs, *this); -} - -void CoordinateReferenceSystem::Serialize(Serializer &serializer) const { - // Only serialize the text definition - serializer.WritePropertyWithDefault(100, "text", text); -} - -CoordinateReferenceSystem CoordinateReferenceSystem::Deserialize(Deserializer &deserializer) { - string text; - deserializer.ReadPropertyWithDefault(100, "text", text); - CoordinateReferenceSystem result; - // If this fails for whatever reason, just return an invalid CRS - if (!TryParse(text, result)) { - result.text = ""; - result.type = CoordinateReferenceSystemType::INVALID; - } - return result; -} - //---------------------------------------------------------------------------------------------------------------------- // WKT2:2019 Parsing //---------------------------------------------------------------------------------------------------------------------- - +namespace { class WKTKeyword; class WKTNumber; class WKTString; @@ -98,13 +31,13 @@ class WKTValue { template T &As() { D_ASSERT(T::TYPE == type); - return reinterpret_cast(*this); + return static_cast(*this); } template - T &As() const { + const T &As() const { D_ASSERT(T::TYPE == type); - return reinterpret_cast(*this); + return static_cast(*this); } bool IsKeyword() const { @@ -182,25 +115,27 @@ class WKTParser { static unique_ptr Parse(const string &wkt) { WKTParser parser(wkt.c_str(), wkt.size()); - // Skip leading whitespace + // Skip initial whitespace parser.SkipWhitespace(); // Parse the root node - return parser.ParseNode(); + auto node = parser.ParseNode(); + + return node; } private: const char *beg; const char *end; const char *pos; + uint32_t depth; private: - WKTParser(const char *text, size_t size) : beg(text), end(text + size), pos(text) { - SkipWhitespace(); + WKTParser(const char *text, size_t size) : beg(text), end(text + size), pos(text), depth(0) { } bool TryMatch(char c) { - if (pos < end && tolower(*pos) == tolower(c)) { + if (pos < end && *pos == c) { pos++; SkipWhitespace(); // remove trailing whitespace return true; @@ -219,8 +154,13 @@ class WKTParser { bool TryMatchText(string &result) { const auto start = pos; - while (pos < end && (isalpha(*pos) || *pos == '_')) { + // First character must be alphabetic or underscore + if (pos < end && (isalpha(*pos) || *pos == '_')) { pos++; + // Subsequent characters can also include digits + while (pos < end && (isalnum(*pos) || *pos == '_')) { + pos++; + } } if (pos == start) { // Didnt match any text @@ -237,13 +177,28 @@ class WKTParser { return nullptr; } const char *start = pos; - while (pos < end && *pos != '"') { - pos++; + string result; + while (pos < end) { + if (*pos == '"') { + // Check for escaped quote (doubled quote) + if (pos + 1 < end && *(pos + 1) == '"') { + // Append everything up to and including one quote + result.append(start, UnsafeNumericCast(pos - start + 1)); + pos += 2; // Skip both quotes + start = pos; + } else { + // End of string + break; + } + } else { + pos++; + } } if (pos == end) { throw InvalidInputException("Unterminated string starting at position %zu", start - beg); } - auto result = string(start, UnsafeNumericCast(pos - start)); + // Append any remaining content before the closing quote + result.append(start, UnsafeNumericCast(pos - start)); Match('"'); SkipWhitespace(); @@ -304,6 +259,11 @@ class WKTParser { } unique_ptr ParseNode() { + // Increment depth to avoid stack overflow on malicious input + if (depth++ > 1000) { + throw InvalidInputException("WKT input is too deeply nested to parse"); + } + unique_ptr node = nullptr; node = ParseStringNode(); @@ -371,6 +331,9 @@ static string TryExtractIDFromWKTNode(const WKTKeyword &keyword) { return string(); } + +} // namespace + bool CoordinateReferenceSystem::TryParseWKT2(const string &text, CoordinateReferenceSystem &result) { const auto node = WKTParser::Parse(text); @@ -456,12 +419,12 @@ bool CoordinateReferenceSystem::TryParseWKT2(const string &text, CoordinateRefer } result.type = CoordinateReferenceSystemType::WKT2_2019; - result.name = name; - result.text = text; + result.identifier = name; + result.definition = text; // Also trim text // TODO: Normalize WKT Input - StringUtil::Trim(result.text); + StringUtil::Trim(result.definition); return true; } @@ -478,13 +441,14 @@ bool CoordinateReferenceSystem::TryParseWKT2(const string &text, CoordinateRefer // Pick name as fallback name = first->As().GetValue(); } - result.name = name; + result.type = CoordinateReferenceSystemType::WKT2_2019; - result.text = text; + result.identifier = name; + result.definition = text; // Also trim text // TODO: Normalize WKT Input - StringUtil::Trim(result.text); + StringUtil::Trim(result.definition); return true; } @@ -552,7 +516,7 @@ bool CoordinateReferenceSystem::TryParsePROJJSON(const string &text, CoordinateR if (name_val && yyjson_is_str(name_val)) { const char *name_str = yyjson_get_str(name_val); if (name_str) { - result.name = string(name_str); + result.identifier = string(name_str); } } @@ -564,17 +528,17 @@ bool CoordinateReferenceSystem::TryParsePROJJSON(const string &text, CoordinateR const auto auth_str = yyjson_get_str(auth_val); if (auth_str) { - result.code = string(auth_str); + result.identifier = string(auth_str); const auto code_val = yyjson_obj_get(id_val, "code"); if (code_val && yyjson_is_int(code_val)) { const auto code_int = yyjson_get_int(code_val); - result.code += ":" + StringUtil::Format("%d", code_int); + result.identifier += ":" + StringUtil::Format("%d", code_int); } if (code_val && yyjson_is_str(code_val)) { const auto code_str = yyjson_get_str(code_val); if (code_str) { - result.code += ":" + string(code_str); + result.identifier += ":" + string(code_str); } } } @@ -591,7 +555,7 @@ bool CoordinateReferenceSystem::TryParsePROJJSON(const string &text, CoordinateR return false; } - result.text = string(json_text, json_size); + result.definition = string(json_text, json_size); free(json_text); return true; @@ -639,15 +603,170 @@ bool CoordinateReferenceSystem::TryParseAuthCode(const string &text, CoordinateR if (auth_valid && code_valid) { // Valid AUTH:CODE result.type = CoordinateReferenceSystemType::AUTH_CODE; - result.text = string(beg, UnsafeNumericCast(end - beg)); - result.code = result.text; + result.definition = string(beg, UnsafeNumericCast(end - beg)); return true; } break; } } - return false; } +//---------------------------------------------------------------------------------------------------------------------- +// Coordinate Reference System Parsing +//---------------------------------------------------------------------------------------------------------------------- +void CoordinateReferenceSystem::ParseDefinition(const string &definition, CoordinateReferenceSystem &result) { + if (definition.empty()) { + result.type = CoordinateReferenceSystemType::INVALID; + return; + } + + // Check if the text is all whitespace + auto all_space = true; + for (const auto c : definition) { + if (!StringUtil::CharacterIsSpace(c)) { + all_space = false; + break; + } + } + + if (all_space) { + result.type = CoordinateReferenceSystemType::INVALID; + return; + } + + if (TryParsePROJJSON(definition, result)) { + return; + } + + if (TryParseAuthCode(definition, result)) { + return; + } + + // TODO: Also strip formatting + if (TryParseWKT2(definition, result)) { + return; + } + + // Otherwise, treat this as an opaque identifier, and don't set an explicit id + result.type = CoordinateReferenceSystemType::SRID; + result.definition = definition; +} + +void CoordinateReferenceSystem::Serialize(Serializer &serializer) const { + serializer.WritePropertyWithDefault(100, "definition", definition, string()); +} + +CoordinateReferenceSystem CoordinateReferenceSystem::Deserialize(Deserializer &deserializer) { + string definition; + deserializer.ReadPropertyWithExplicitDefault(100, "definition", definition, string()); + + // If this fails for whatever reason, just return an invalid CRS + CoordinateReferenceSystem result; + try { + ParseDefinition(definition, result); + } catch (...) { + result.definition = ""; + result.type = CoordinateReferenceSystemType::INVALID; + } + return result; +} + +//---------------------------------------------------------------------------------------------------------------------- +// Coordinate Reference System Manager +//---------------------------------------------------------------------------------------------------------------------- + +unique_ptr CoordinateReferenceSystem::TryConvert(ClientContext &context, + const CoordinateReferenceSystem &source_crs, + CoordinateReferenceSystemType target_type) { + if (source_crs.type == target_type && source_crs.IsComplete()) { + // No conversion needed + return make_uniq(source_crs); + } + + auto &catalog = Catalog::GetSystemCatalog(context); + auto entry = catalog.GetEntry(context, CatalogType::COORDINATE_SYSTEM_ENTRY, DEFAULT_SCHEMA, + source_crs.GetIdentifier(), OnEntryNotFound::RETURN_NULL); + if (!entry) { + return nullptr; + } + + auto &crs_entry = entry->Cast(); + + switch (target_type) { + case CoordinateReferenceSystemType::AUTH_CODE: { + if (crs_entry.authority.empty() || crs_entry.code.empty()) { + return nullptr; + } + return make_uniq(crs_entry.authority + ":" + crs_entry.code); + } + case CoordinateReferenceSystemType::SRID: { + return make_uniq(crs_entry.name); + } + case CoordinateReferenceSystemType::PROJJSON: { + if (crs_entry.projjson_definition.empty()) { + return nullptr; + } + return make_uniq(crs_entry.projjson_definition); + } + case CoordinateReferenceSystemType::WKT2_2019: { + if (crs_entry.wkt2_2019_definition.empty()) { + return nullptr; + } + return make_uniq(crs_entry.wkt2_2019_definition); + } + default: + break; + } + + return nullptr; +} + +unique_ptr CoordinateReferenceSystem::TryConvert(ClientContext &context, + const string &source_crs, + CoordinateReferenceSystemType target_type) { + const CoordinateReferenceSystem source(source_crs); + return TryConvert(context, source, target_type); +} + +unique_ptr CoordinateReferenceSystem::TryIdentify(ClientContext &context, + const string &source_crs) { + CoordinateReferenceSystem source(source_crs); + + // We couldnt even parse the CRS + if (source.GetType() == CoordinateReferenceSystemType::INVALID) { + return nullptr; + } + + // We always want to identify the CRS as short as possible, so first check for AUTH:CODE + auto auth_crs = TryConvert(context, source, CoordinateReferenceSystemType::AUTH_CODE); + if (auth_crs) { + return auth_crs; + } + + // Next, check for SRID + auto srid_crs = TryConvert(context, source, CoordinateReferenceSystemType::SRID); + if (srid_crs) { + return srid_crs; + } + + // Otherwise, PROJJSON + auto projjson_crs = TryConvert(context, source, CoordinateReferenceSystemType::PROJJSON); + if (projjson_crs) { + return projjson_crs; + } + + // Finally, WKT2:2019 + auto wkt2_crs = TryConvert(context, source, CoordinateReferenceSystemType::WKT2_2019); + if (wkt2_crs) { + return wkt2_crs; + } + + if (!source.IsComplete()) { + return nullptr; + } + + return make_uniq(std::move(source)); +} + } // namespace duckdb diff --git a/src/duckdb/src/common/types/row/tuple_data_allocator.cpp b/src/duckdb/src/common/types/row/tuple_data_allocator.cpp index 20f7e5957..59cbb5510 100644 --- a/src/duckdb/src/common/types/row/tuple_data_allocator.cpp +++ b/src/duckdb/src/common/types/row/tuple_data_allocator.cpp @@ -55,7 +55,7 @@ void TupleDataAllocator::DestroyRowBlocks(const idx_t row_block_begin, const idx for (idx_t block_idx = row_block_begin; block_idx < row_block_end; block_idx++) { auto &block = row_blocks[block_idx]; if (block.handle) { - block.handle->SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); + block.handle->GetMemory().SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); } } } @@ -68,7 +68,7 @@ void TupleDataAllocator::DestroyHeapBlocks(const idx_t heap_block_begin, const i for (idx_t block_idx = heap_block_begin; block_idx < heap_block_end; block_idx++) { auto &block = heap_blocks[block_idx]; if (block.handle) { - block.handle->SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); + block.handle->GetMemory().SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); } } } @@ -229,7 +229,8 @@ TupleDataAllocator::BuildChunkPart(TupleDataSegment &segment, TupleDataPinState if (row_blocks.empty() || row_blocks.back().RemainingCapacity() < layout.GetRowWidth()) { CreateRowBlock(segment); if (partition_index.IsValid()) { // Set the eviction queue index logarithmically using RadixBits - row_blocks.back().handle->SetEvictionQueueIndex(RadixPartitioning::RadixBits(partition_index.GetIndex())); + row_blocks.back().handle->GetMemory().SetEvictionQueueIndex( + RadixPartitioning::RadixBits(partition_index.GetIndex())); } } result.row_block_index = NumericCast(row_blocks.size() - 1); @@ -284,7 +285,7 @@ TupleDataAllocator::BuildChunkPart(TupleDataSegment &segment, TupleDataPinState const auto size = MaxValue(block_size, heap_sizes[append_offset]); CreateHeapBlock(segment, size); if (partition_index.IsValid()) { // Set the eviction queue index logarithmically using RadixBits - heap_blocks.back().handle->SetEvictionQueueIndex( + heap_blocks.back().handle->GetMemory().SetEvictionQueueIndex( RadixPartitioning::RadixBits(partition_index.GetIndex())); } } @@ -764,7 +765,7 @@ void TupleDataAllocator::ReleaseOrStoreHandlesInternal(TupleDataSegment &segment break; case TupleDataPinProperties::DESTROY_AFTER_DONE: // Prevent it from being added to the eviction queue - blocks[block_id].handle->SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); + blocks[block_id].handle->GetMemory().SetDestroyBufferUpon(DestroyBufferUpon::UNPIN); // Destroy blocks[block_id].handle.reset(); break; diff --git a/src/duckdb/src/common/types/row/tuple_data_collection.cpp b/src/duckdb/src/common/types/row/tuple_data_collection.cpp index a3b760d06..6301d3170 100644 --- a/src/duckdb/src/common/types/row/tuple_data_collection.cpp +++ b/src/duckdb/src/common/types/row/tuple_data_collection.cpp @@ -32,7 +32,10 @@ TupleDataCollection::TupleDataCollection(ClientContext &context, shared_ptr::Schedule(scheduler, segments); + static constexpr idx_t PARALLEL_DESTROY_THRESHOLD = 1048576; + if (count > PARALLEL_DESTROY_THRESHOLD) { + ParallelDestroyTask::Schedule(scheduler, segments); + } } void TupleDataCollection::Initialize() { diff --git a/src/duckdb/src/common/types/row/tuple_data_scatter_gather.cpp b/src/duckdb/src/common/types/row/tuple_data_scatter_gather.cpp index 3c967d448..99e694121 100644 --- a/src/duckdb/src/common/types/row/tuple_data_scatter_gather.cpp +++ b/src/duckdb/src/common/types/row/tuple_data_scatter_gather.cpp @@ -29,7 +29,7 @@ static void TupleDataValueStore(const T &source, data_t *__restrict const &row_l template <> inline void TupleDataValueStore(const string_t &source, data_t *__restrict const &row_location, const idx_t &offset_in_row, data_ptr_t &heap_location) { -#ifdef D_ASSERT_IS_ENABLED +#ifdef DEBUG source.VerifyCharacters(); #endif if (source.IsInlined()) { @@ -54,7 +54,7 @@ static void TupleDataWithinListValueStore(const T &source, const data_ptr_t &loc template <> inline void TupleDataWithinListValueStore(const string_t &source, const data_ptr_t &location, data_ptr_t &heap_location) { -#ifdef D_ASSERT_IS_ENABLED +#ifdef DEBUG source.VerifyCharacters(); #endif Store(UnsafeNumericCast(source.GetSize()), location); @@ -64,14 +64,14 @@ inline void TupleDataWithinListValueStore(const string_t &source, const data_ptr template void TupleDataValueVerify(const LogicalType &, const T &) { -#ifdef D_ASSERT_IS_ENABLED +#ifdef DEBUG // NOP #endif } template <> inline void TupleDataValueVerify(const LogicalType &type, const string_t &value) { -#ifdef D_ASSERT_IS_ENABLED +#ifdef DEBUG if (type.id() == LogicalTypeId::VARCHAR) { value.Verify(); } @@ -516,7 +516,7 @@ void TupleDataCollection::CollectionWithinCollectionComputeHeapSizes(Vector &hea D_ASSERT(source_format.children.size() == 1); auto &child_format = source_format.children[0]; #ifdef D_ASSERT_IS_ENABLED - // In debug mode this should be deleted by ResetCombinedListData + // Should be deleted by ResetCombinedListData if assertions are enabled D_ASSERT(!child_format.combined_list_data); #endif if (!child_format.combined_list_data) { @@ -647,7 +647,7 @@ static void InitializeValidityMask(const data_ptr_t row_locations[], const idx_t void TupleDataCollection::Scatter(TupleDataChunkState &chunk_state, const DataChunk &new_chunk, const SelectionVector &append_sel, const idx_t append_count) const { -#ifdef D_ASSERT_IS_ENABLED +#ifdef DEBUG Vector heap_locations_copy(LogicalType::POINTER); if (!layout.AllConstant()) { const auto heap_locations = FlatVector::GetData(chunk_state.heap_locations); @@ -686,7 +686,7 @@ void TupleDataCollection::Scatter(TupleDataChunkState &chunk_state, const DataCh } } -#ifdef D_ASSERT_IS_ENABLED +#ifdef DEBUG // Verify that the size of the data written to the heap is the same as the size we computed it would be if (!layout.AllConstant()) { const auto original_heap_locations = FlatVector::GetData(heap_locations_copy); diff --git a/src/duckdb/src/common/types/type_manager.cpp b/src/duckdb/src/common/types/type_manager.cpp new file mode 100644 index 000000000..255e41c85 --- /dev/null +++ b/src/duckdb/src/common/types/type_manager.cpp @@ -0,0 +1,117 @@ +#include "duckdb/common/types/type_manager.hpp" +#include "duckdb/function/cast/cast_function_set.hpp" +#include "duckdb/parser/parser.hpp" +#include "duckdb/planner/binder.hpp" +#include "duckdb/main/config.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/main/database.hpp" + +namespace duckdb { + +CastFunctionSet &TypeManager::GetCastFunctions() { + return *cast_functions; +} + +static LogicalType TransformStringToUnboundType(const string &str) { + if (StringUtil::Lower(str) == "null") { + return LogicalType::SQLNULL; + } + ColumnList column_list; + try { + column_list = Parser::ParseColumnList("dummy " + str); + } catch (const std::runtime_error &e) { + const vector suggested_types {"BIGINT", + "INT8", + "LONG", + "BIT", + "BITSTRING", + "BLOB", + "BYTEA", + "BINARY,", + "VARBINARY", + "BOOLEAN", + "BOOL", + "LOGICAL", + "DATE", + "DECIMAL(prec, scale)", + "DOUBLE", + "FLOAT8", + "FLOAT", + "FLOAT4", + "REAL", + "HUGEINT", + "INTEGER", + "INT4", + "INT", + "SIGNED", + "INTERVAL", + "SMALLINT", + "INT2", + "SHORT", + "TIME", + "TIMESTAMPTZ", + "TIMESTAMP", + "DATETIME", + "TINYINT", + "INT1", + "UBIGINT", + "UHUGEINT", + "UINTEGER", + "USMALLINT", + "UTINYINT", + "UUID", + "VARCHAR", + "CHAR", + "BPCHAR", + "TEXT", + "STRING", + "MAP(INTEGER, VARCHAR)", + "UNION(num INTEGER, text VARCHAR)"}; + std::ostringstream error; + error << "Value \"" << str << "\" can not be converted to a DuckDB Type." << '\n'; + error << "Possible examples as suggestions: " << '\n'; + auto suggestions = StringUtil::TopNJaroWinkler(suggested_types, str); + for (auto &suggestion : suggestions) { + error << "* " << suggestion << '\n'; + } + throw InvalidInputException(error.str()); + } + return column_list.GetColumn(LogicalIndex(0)).Type(); +} + +// This has to be called with a level of indirection (through "parse_function") in order to avoid being included in +// extensions that statically link the core DuckDB library. +static LogicalType ParseLogicalTypeInternal(const string &type_str, ClientContext &context) { + auto type = TransformStringToUnboundType(type_str); + if (type.IsUnbound()) { + if (!context.transaction.HasActiveTransaction()) { + throw InternalException( + "Context does not have a transaction active, try running ClientContext::BindLogicalType instead"); + } + auto binder = Binder::CreateBinder(context, nullptr); + binder->BindLogicalType(type); + } + return type; +} + +LogicalType TypeManager::ParseLogicalType(const string &type_str, ClientContext &context) const { + return parse_function(type_str, context); +} + +TypeManager &TypeManager::Get(DatabaseInstance &db) { + return DBConfig::GetConfig(db).GetTypeManager(); +} + +TypeManager &TypeManager::Get(ClientContext &context) { + return DBConfig::GetConfig(context).GetTypeManager(); +} + +TypeManager::TypeManager(DBConfig &config_p) { + cast_functions = make_uniq(config_p); + parse_function = ParseLogicalTypeInternal; +} + +TypeManager::~TypeManager() { +} + +} // namespace duckdb diff --git a/src/duckdb/src/common/types/value.cpp b/src/duckdb/src/common/types/value.cpp index acedfe835..0ec8310d3 100644 --- a/src/duckdb/src/common/types/value.cpp +++ b/src/duckdb/src/common/types/value.cpp @@ -26,8 +26,12 @@ #include "duckdb/common/types/bignum.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" +#include "duckdb/common/serializer/binary_serializer.hpp" +#include "duckdb/common/serializer/binary_deserializer.hpp" +#include "duckdb/common/serializer/memory_stream.hpp" #include "duckdb/common/types/string.hpp" #include "duckdb/common/types/value_map.hpp" +#include "duckdb/function/scalar/variant_utils.hpp" #include #include @@ -935,6 +939,25 @@ Value Value::GEOMETRY(const_data_ptr_t data, idx_t len) { return result; } +Value Value::TYPE(const LogicalType &type) { + MemoryStream stream; + BinarySerializer::Serialize(type, stream); + auto data_ptr = const_char_ptr_cast(stream.GetData()); + auto data_len = stream.GetPosition(); + + Value result(LogicalType::TYPE()); + result.is_null = false; + result.value_info_ = make_shared_ptr(string(data_ptr, data_len)); + return result; +} + +Value Value::TYPE(const string_t &serialized_type) { + Value result(LogicalType::TYPE()); + result.is_null = false; + result.value_info_ = make_shared_ptr(serialized_type.GetString()); + return result; +} + Value Value::BLOB(const string &data) { Value result(LogicalType::BLOB); result.is_null = false; @@ -1645,7 +1668,17 @@ string Value::ToSQLString() const { } return "'" + StringUtil::Replace(ToString(), "'", "''") + "'"; } - case LogicalTypeId::VARIANT: + case LogicalTypeId::VARIANT: { + string ret = "VARIANT("; + Vector tmp(*this); + RecursiveUnifiedVectorFormat format; + Vector::RecursiveToUnifiedFormat(tmp, 1, format); + UnifiedVariantVectorData vector_data(format); + auto val = VariantUtils::ConvertVariantToValue(vector_data, 0, 0); + ret += val.ToString(); + ret += ")"; + return ret; + } case LogicalTypeId::STRUCT: { bool is_unnamed = StructType::IsUnnamed(type_); string ret = is_unnamed ? "(" : "{"; @@ -1786,6 +1819,19 @@ const string &StringValue::Get(const Value &value) { return value.value_info_->Get().GetString(); } +LogicalType TypeValue::GetType(const Value &value) { + if (value.is_null) { + throw InternalException("Calling TypeValue::GetType on a NULL value"); + } + D_ASSERT(value.type().id() == LogicalTypeId::TYPE); + D_ASSERT(value.value_info_); + auto &type_str = value.value_info_->Get().GetString(); + auto str = string_t(type_str); + MemoryStream stream(data_ptr_cast(str.GetDataWriteable()), str.GetSize()); + BinaryDeserializer deserializer(stream); + return LogicalType::Deserialize(deserializer); +} + date_t DateValue::Get(const Value &value) { return value.GetValueUnsafe(); } @@ -2034,7 +2080,7 @@ void Value::Reinterpret(LogicalType new_type) { this->type_ = std::move(new_type); } -const LogicalType &GetChildType(const LogicalType &parent_type, idx_t i) { +static const LogicalType &GetChildType(const LogicalType &parent_type, idx_t i) { switch (parent_type.InternalType()) { case PhysicalType::LIST: return ListType::GetChildType(parent_type); @@ -2047,7 +2093,7 @@ const LogicalType &GetChildType(const LogicalType &parent_type, idx_t i) { } } -bool SerializeTypeMatches(const LogicalType &expected_type, const LogicalType &actual_type) { +static bool SerializeTypeMatches(const LogicalType &expected_type, const LogicalType &actual_type) { if (expected_type.id() != actual_type.id()) { // type id needs to be the same return false; @@ -2087,6 +2133,14 @@ void Value::SerializeInternal(Serializer &serializer, bool serialize_type) const if (IsNull()) { return; } + + if (type_.id() == LogicalTypeId::TYPE) { + // special case for TYPE values: serialize the type as a nested object + auto type_value = TypeValue::GetType(*this); + serializer.WriteProperty(102, "value", type_value); + return; + } + switch (type_.InternalType()) { case PhysicalType::BIT: throw InternalException("BIT type should not be serialized"); @@ -2170,6 +2224,13 @@ Value Value::Deserialize(Deserializer &deserializer) { return new_value; } new_value.is_null = false; + + if (type.id() == LogicalTypeId::TYPE) { + // special case for TYPE values: deserialize the type as a nested object + auto type_value = deserializer.ReadProperty(102, "value"); + return Value::TYPE(type_value); + } + switch (type.InternalType()) { case PhysicalType::BIT: throw InternalException("BIT type should not be deserialized"); diff --git a/src/duckdb/src/common/types/variant/variant_value.cpp b/src/duckdb/src/common/types/variant/variant_value.cpp index fd5734e19..46430275a 100644 --- a/src/duckdb/src/common/types/variant/variant_value.cpp +++ b/src/duckdb/src/common/types/variant/variant_value.cpp @@ -22,11 +22,17 @@ namespace duckdb { void VariantValue::AddChild(const string &key, VariantValue &&val) { D_ASSERT(value_type == VariantValueType::OBJECT); + if (val.IsMissing()) { + throw InternalException("Adding a missing value to an object"); + } object_children.emplace(key, std::move(val)); } void VariantValue::AddItem(VariantValue &&val) { D_ASSERT(value_type == VariantValueType::ARRAY); + if (val.IsMissing()) { + throw InternalException("Adding a missing value to an array"); + } array_items.push_back(std::move(val)); } @@ -216,6 +222,8 @@ static void AnalyzeValue(const VariantValue &value, idx_t row, DataChunk &offset } break; } + case VariantValueType::MISSING: + throw InternalException("Unexpected MISSING value in Variant AnalyzeValue"); default: throw InternalException("VariantValueType not handled"); } diff --git a/src/duckdb/src/common/types/vector.cpp b/src/duckdb/src/common/types/vector.cpp index 5ae9d0643..8caaa55b8 100644 --- a/src/duckdb/src/common/types/vector.cpp +++ b/src/duckdb/src/common/types/vector.cpp @@ -804,6 +804,10 @@ Value Vector::GetValueInternal(const Vector &v_p, idx_t index_p) { } return Value::ARRAY(ArrayType::GetChildType(type), std::move(children)); } + case LogicalTypeId::TYPE: { + auto blob = reinterpret_cast(data)[index]; + return Value::TYPE(blob); + } default: throw InternalException("Unimplemented type for value access"); } diff --git a/src/duckdb/src/common/vector_operations/is_distinct_from.cpp b/src/duckdb/src/common/vector_operations/is_distinct_from.cpp index d08a2d276..538f5f394 100644 --- a/src/duckdb/src/common/vector_operations/is_distinct_from.cpp +++ b/src/duckdb/src/common/vector_operations/is_distinct_from.cpp @@ -1,6 +1,8 @@ #include "duckdb/common/uhugeint.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/operator/comparison_operators.hpp" +#include "duckdb/common/value_operations/value_operations.hpp" +#include "duckdb/function/scalar/variant_utils.hpp" namespace duckdb { @@ -862,6 +864,101 @@ idx_t DistinctSelectArray(Vector &left, Vector &right, idx_t count, const Select return match_count; } +template +idx_t DistinctSelectVariant(Vector &left, Vector &right, idx_t count, const SelectionVector &sel, + OptionalSelection &true_opt, OptionalSelection &false_opt, + optional_ptr null_mask) { + idx_t true_count = 0; + idx_t false_count = 0; + + // Convert vectors to unified format for easier access + RecursiveUnifiedVectorFormat left_recursive_data, right_recursive_data; + Vector::RecursiveToUnifiedFormat(left, count, left_recursive_data); + Vector::RecursiveToUnifiedFormat(right, count, right_recursive_data); + + UnifiedVariantVectorData left_variant(left_recursive_data); + UnifiedVariantVectorData right_variant(right_recursive_data); + + auto &left_data = left_recursive_data.unified; + auto &right_data = right_recursive_data.unified; + for (idx_t i = 0; i < count; i++) { + auto result_idx = sel.get_index(i); + auto left_idx = left_data.sel->get_index(i); + auto right_idx = right_data.sel->get_index(i); + + // Check for NULL values + bool left_null = !left_data.validity.RowIsValid(left_idx); + bool right_null = !right_data.validity.RowIsValid(right_idx); + + bool comparison_result; + if (left_null || right_null) { + // Handle NULL semantics based on operation type + if (std::is_same::value) { + comparison_result = !(left_null && right_null); + } else if (std::is_same::value) { + comparison_result = (left_null && right_null); + } else { + // For ordering operations, NULLs are treated as maximal + if (left_null && right_null) { + comparison_result = false; // NULL == NULL for ordering + } else if (left_null) { + // NULL > anything, so left_null means left is greater + comparison_result = std::is_same::value || + std::is_same::value; + } else { + // right_null, so right is greater + comparison_result = std::is_same::value || + std::is_same::value; + } + } + } else { + // Both non-NULL, convert to Values and use appropriate Value operation + auto left_val = VariantUtils::ConvertVariantToValue(left_variant, i, 0); + auto right_val = VariantUtils::ConvertVariantToValue(right_variant, i, 0); + + LogicalType max_logical_type; + auto res = LogicalType::TryGetMaxLogicalTypeUnchecked(left_val.type(), right_val.type(), max_logical_type); + if (!res) { + throw InvalidInputException( + "Can't compare values of type %s (%s) and type %s (%s) - an explicit cast is required", + left_val.type().ToString(), left_val.ToString(), right_val.type().ToString(), right_val.ToString()); + } + + if (std::is_same::value) { + comparison_result = ValueOperations::DistinctFrom(left_val, right_val); + } else if (std::is_same::value) { + comparison_result = ValueOperations::NotDistinctFrom(left_val, right_val); + } else if (std::is_same::value) { + comparison_result = ValueOperations::DistinctGreaterThan(left_val, right_val); + } else if (std::is_same::value) { + comparison_result = ValueOperations::DistinctGreaterThanEquals(left_val, right_val); + } else if (std::is_same::value) { + comparison_result = ValueOperations::DistinctLessThan(left_val, right_val); + } else if (std::is_same::value) { + comparison_result = ValueOperations::DistinctLessThanEquals(left_val, right_val); + } else { + throw InternalException("Unsupported operation for VARIANT comparison"); + } + } + + if (comparison_result) { + true_opt.Append(true_count, result_idx); + } else { + false_opt.Append(false_count, result_idx); + } + + // Set null mask if needed + if (null_mask && (left_null || right_null)) { + null_mask->SetInvalid(result_idx); + } + } + + true_opt.Advance(true_count); + false_opt.Advance(false_count); + + return true_count; +} + template idx_t DistinctSelectNested(Vector &left, Vector &right, optional_ptr sel, const idx_t count, optional_ptr true_sel, optional_ptr false_sel, @@ -899,10 +996,16 @@ idx_t DistinctSelectNested(Vector &left, Vector &right, optional_ptr(l_not_null, r_not_null, unknown, maybe_vec, true_opt, false_opt, null_mask); break; - case PhysicalType::STRUCT: + case PhysicalType::STRUCT: { + if (left_type.id() == LogicalTypeId::VARIANT) { + match_count += + DistinctSelectVariant(l_not_null, r_not_null, unknown, *sel, true_opt, false_opt, null_mask); + break; + } match_count += DistinctSelectStruct(l_not_null, r_not_null, unknown, maybe_vec, true_opt, false_opt, null_mask); break; + } case PhysicalType::ARRAY: match_count += DistinctSelectArray(l_not_null, r_not_null, unknown, maybe_vec, true_opt, false_opt, null_mask); diff --git a/src/duckdb/src/common/virtual_file_system.cpp b/src/duckdb/src/common/virtual_file_system.cpp index 6374ec963..abb9fdfa8 100644 --- a/src/duckdb/src/common/virtual_file_system.cpp +++ b/src/duckdb/src/common/virtual_file_system.cpp @@ -6,16 +6,112 @@ #include "duckdb/common/string_util.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/storage/caching_file_system_wrapper.hpp" +#include "duckdb/common/multi_file/multi_file_list.hpp" namespace duckdb { +struct FileSystemHandle { + explicit FileSystemHandle(unique_ptr fs) : file_system(std::move(fs)) { + } + + unique_ptr file_system; +}; + +//! The FileSystemRegistry holds the set of file systems that are registered. +//! Note that it should be treated as read-only. +//! When a change is made (e.g. by registering new file system) a copy of the registry is made +struct FileSystemRegistry { + explicit FileSystemRegistry(unique_ptr fs) + : default_fs(make_shared_ptr(std::move(fs))) { + } + + vector> sub_systems; + map> compressed_fs; + const shared_ptr default_fs; + unordered_set disabled_file_systems; + +public: + shared_ptr RegisterSubSystem(unique_ptr fs) const; + shared_ptr RegisterSubSystem(FileCompressionType compression_type, + unique_ptr fs) const; + shared_ptr SetDisabledFileSystems(const vector &names) const; + shared_ptr ExtractSubSystem(const string &name, unique_ptr &result) const; +}; + +shared_ptr FileSystemRegistry::RegisterSubSystem(unique_ptr fs) const { + auto new_registry = make_shared_ptr(*this); + const auto &name = fs->GetName(); + for (auto &sub_system : new_registry->sub_systems) { + if (sub_system->file_system->GetName() == name) { + throw InvalidInputException("Filesystem with name %s has already been registered, cannot re-register!", + name); + } + } + new_registry->sub_systems.push_back(make_shared_ptr(std::move(fs))); + return new_registry; +} + +shared_ptr FileSystemRegistry::RegisterSubSystem(FileCompressionType compression_type, + unique_ptr fs) const { + auto new_registry = make_shared_ptr(*this); + new_registry->compressed_fs[compression_type] = make_shared_ptr(std::move(fs)); + return new_registry; +} + +shared_ptr FileSystemRegistry::SetDisabledFileSystems(const vector &names) const { + auto new_registry = make_shared_ptr(*this); + unordered_set new_disabled_file_systems; + for (auto &name : names) { + if (name.empty()) { + continue; + } + if (new_disabled_file_systems.find(name) != new_disabled_file_systems.end()) { + throw InvalidInputException("Duplicate disabled file system \"%s\"", name); + } + new_disabled_file_systems.insert(name); + } + for (auto &disabled_fs : disabled_file_systems) { + if (new_disabled_file_systems.find(disabled_fs) == new_disabled_file_systems.end()) { + throw InvalidInputException("File system \"%s\" has been disabled previously, it cannot be re-enabled", + disabled_fs); + } + } + new_registry->disabled_file_systems = std::move(new_disabled_file_systems); + return new_registry; +} + +shared_ptr FileSystemRegistry::ExtractSubSystem(const string &name, + unique_ptr &result) const { + auto new_registry = make_shared_ptr(*this); + // If the subsystem has been disabled, we don't allow extraction and return nullptr here. + if (disabled_file_systems.find(name) != disabled_file_systems.end()) { + return nullptr; + } + + for (auto iter = new_registry->sub_systems.begin(); iter != new_registry->sub_systems.end(); ++iter) { + auto &cur_filesystem = (*iter)->file_system; + if (cur_filesystem->GetName() == name) { + result = std::move(cur_filesystem); + new_registry->sub_systems.erase(iter); + return new_registry; + } + } + + // Requested subfilesystem is not registered. + return nullptr; +} + VirtualFileSystem::VirtualFileSystem() : VirtualFileSystem(FileSystem::CreateLocal()) { } -VirtualFileSystem::VirtualFileSystem(unique_ptr &&inner) : default_fs(std::move(inner)) { +VirtualFileSystem::VirtualFileSystem(unique_ptr &&inner) + : file_system_registry(make_shared_ptr(std::move(inner))) { VirtualFileSystem::RegisterSubSystem(FileCompressionType::GZIP, make_uniq()); } +VirtualFileSystem::~VirtualFileSystem() { +} + unique_ptr VirtualFileSystem::OpenFileExtended(const OpenFileInfo &file, FileOpenFlags flags, optional_ptr opener) { auto compression = flags.Compression(); @@ -38,7 +134,8 @@ unique_ptr VirtualFileSystem::OpenFileExtended(const OpenFileInfo &f // open the base file handle in UNCOMPRESSED mode flags.SetCompression(FileCompressionType::UNCOMPRESSED); - auto &internal_filesystem = FindFileSystem(file.path, opener); + auto registry = file_system_registry.atomic_load(); + auto &internal_filesystem = FindFileSystem(registry, file.path, opener); // File handle gets created. unique_ptr file_handle = nullptr; @@ -61,8 +158,8 @@ unique_ptr VirtualFileSystem::OpenFileExtended(const OpenFileInfo &f if (file_handle->GetType() == FileType::FILE_TYPE_FIFO) { file_handle = PipeFileSystem::OpenPipe(context, std::move(file_handle)); } else if (compression != FileCompressionType::UNCOMPRESSED) { - auto entry = compressed_fs.find(compression); - if (entry == compressed_fs.end()) { + auto entry = registry->compressed_fs.find(compression); + if (entry == registry->compressed_fs.end()) { if (compression == FileCompressionType::ZSTD) { throw NotImplementedException( "Attempting to open a compressed file, but the compression type is not supported.\nConsider " @@ -71,7 +168,8 @@ unique_ptr VirtualFileSystem::OpenFileExtended(const OpenFileInfo &f throw NotImplementedException( "Attempting to open a compressed file, but the compression type is not supported"); } - file_handle = entry->second->OpenCompressedFile(context, std::move(file_handle), flags.OpenForWriting()); + auto &compressed_fs = *entry->second->file_system; + file_handle = compressed_fs.OpenCompressedFile(context, std::move(file_handle), flags.OpenForWriting()); } return file_handle; } @@ -118,14 +216,14 @@ void VirtualFileSystem::FileSync(FileHandle &handle) { // need to look up correct fs for this bool VirtualFileSystem::DirectoryExists(const string &directory, optional_ptr opener) { - return FindFileSystem(directory).DirectoryExists(directory, opener); + return FindFileSystem(directory, opener).DirectoryExists(directory, opener); } void VirtualFileSystem::CreateDirectory(const string &directory, optional_ptr opener) { - FindFileSystem(directory).CreateDirectory(directory, opener); + FindFileSystem(directory, opener).CreateDirectory(directory, opener); } void VirtualFileSystem::RemoveDirectory(const string &directory, optional_ptr opener) { - FindFileSystem(directory).RemoveDirectory(directory, opener); + FindFileSystem(directory, opener).RemoveDirectory(directory, opener); } bool VirtualFileSystem::ListFilesExtended(const string &directory, @@ -135,7 +233,7 @@ bool VirtualFileSystem::ListFilesExtended(const string &directory, } void VirtualFileSystem::MoveFile(const string &source, const string &target, optional_ptr opener) { - FindFileSystem(source).MoveFile(source, target, opener); + FindFileSystem(source, opener).MoveFile(source, target, opener); } bool VirtualFileSystem::FileExists(const string &filename, optional_ptr opener) { @@ -143,21 +241,21 @@ bool VirtualFileSystem::FileExists(const string &filename, optional_ptr opener) { - return FindFileSystem(filename).IsPipe(filename, opener); + return FindFileSystem(filename, opener).IsPipe(filename, opener); } void VirtualFileSystem::RemoveFile(const string &filename, optional_ptr opener) { - FindFileSystem(filename).RemoveFile(filename, opener); + FindFileSystem(filename, opener).RemoveFile(filename, opener); } bool VirtualFileSystem::TryRemoveFile(const string &filename, optional_ptr opener) { - return FindFileSystem(filename).TryRemoveFile(filename, opener); + return FindFileSystem(filename, opener).TryRemoveFile(filename, opener); } void VirtualFileSystem::RemoveFiles(const vector &filenames, optional_ptr opener) { reference_map_t> files_by_fs; for (const auto &filename : filenames) { - auto &fs = FindFileSystem(filename); + auto &fs = FindFileSystem(filename, opener); files_by_fs[fs].push_back(filename); } for (auto &entry : files_by_fs) { @@ -166,63 +264,58 @@ void VirtualFileSystem::RemoveFiles(const vector &filenames, optional_pt } string VirtualFileSystem::PathSeparator(const string &path) { - return FindFileSystem(path).PathSeparator(path); + return FindFileSystem(path, nullptr).PathSeparator(path); } -vector VirtualFileSystem::Glob(const string &path, FileOpener *opener) { - return FindFileSystem(path, opener).Glob(path, opener); +string VirtualFileSystem::CanonicalizePath(const string &path_p, optional_ptr opener) { + return FindFileSystem(path_p, opener).CanonicalizePath(path_p, opener); } -void VirtualFileSystem::RegisterSubSystem(unique_ptr fs) { - // Sub-filesystem number is not expected to be huge, also filesystem registration should be called infrequently. - const auto &name = fs->GetName(); - for (auto sub_system = sub_systems.begin(); sub_system != sub_systems.end(); sub_system++) { - if (sub_system->get()->GetName() == name) { - throw InvalidInputException("Filesystem with name %s has already been registered, cannot re-register!", - name); - } - } - sub_systems.push_back(std::move(fs)); +unique_ptr VirtualFileSystem::GlobFilesExtended(const string &path, const FileGlobInput &input, + optional_ptr opener) { + return FindFileSystem(path, opener).Glob(path, input, opener); } -void VirtualFileSystem::UnregisterSubSystem(const string &name) { - for (auto sub_system = sub_systems.begin(); sub_system != sub_systems.end(); sub_system++) { - if (sub_system->get()->GetName() == name) { - sub_systems.erase(sub_system); - return; - } - } - throw InvalidInputException("Could not find filesystem with name %s", name); +void VirtualFileSystem::RegisterSubSystem(unique_ptr fs) { + lock_guard guard(registry_lock); + auto new_registry = file_system_registry->RegisterSubSystem(std::move(fs)); + file_system_registry.atomic_store(new_registry); } void VirtualFileSystem::RegisterSubSystem(FileCompressionType compression_type, unique_ptr fs) { - compressed_fs[compression_type] = std::move(fs); + lock_guard guard(registry_lock); + auto new_registry = file_system_registry->RegisterSubSystem(compression_type, std::move(fs)); + file_system_registry.atomic_store(new_registry); } -unique_ptr VirtualFileSystem::ExtractSubSystem(const string &name) { - // If the subsystem has been disabled, we don't allow extraction and return nullptr here. - if (disabled_file_systems.find(name) != disabled_file_systems.end()) { - return nullptr; - } +void VirtualFileSystem::UnregisterSubSystem(const string &name) { + auto sub_system = ExtractSubSystem(name); - unique_ptr extracted_filesystem; - for (auto iter = sub_systems.begin(); iter != sub_systems.end(); ++iter) { - auto &cur_filesystem = *iter; - if (cur_filesystem->GetName() == name) { - extracted_filesystem = std::move(cur_filesystem); - sub_systems.erase(iter); - return extracted_filesystem; - } - } + lock_guard guard(registry_lock); + unregistered_file_systems.push_back(std::move(sub_system)); +} - // Requested subfilesystem is not registered. - return nullptr; +void VirtualFileSystem::SetDisabledFileSystems(const vector &names) { + lock_guard guard(registry_lock); + auto new_registry = file_system_registry->SetDisabledFileSystems(names); + file_system_registry.atomic_store(new_registry); +} +unique_ptr VirtualFileSystem::ExtractSubSystem(const string &name) { + lock_guard guard(registry_lock); + unique_ptr result; + auto new_registry = file_system_registry->ExtractSubSystem(name, result); + if (new_registry) { + file_system_registry.atomic_store(new_registry); + } + return result; } vector VirtualFileSystem::ListSubSystems() { - vector names(sub_systems.size()); - for (idx_t i = 0; i < sub_systems.size(); i++) { - names[i] = sub_systems[i]->GetName(); + auto registry = file_system_registry.atomic_load(); + auto &sub_systems = registry->sub_systems; + vector names; + for (auto &sub_system : sub_systems) { + names.push_back(sub_system->file_system->GetName()); } return names; } @@ -231,47 +324,34 @@ std::string VirtualFileSystem::GetName() const { return "VirtualFileSystem"; } -void VirtualFileSystem::SetDisabledFileSystems(const vector &names) { - unordered_set new_disabled_file_systems; - for (auto &name : names) { - if (name.empty()) { - continue; - } - if (new_disabled_file_systems.find(name) != new_disabled_file_systems.end()) { - throw InvalidInputException("Duplicate disabled file system \"%s\"", name); - } - new_disabled_file_systems.insert(name); - } - for (auto &disabled_fs : disabled_file_systems) { - if (new_disabled_file_systems.find(disabled_fs) == new_disabled_file_systems.end()) { - throw InvalidInputException("File system \"%s\" has been disabled previously, it cannot be re-enabled", - disabled_fs); - } - } - disabled_file_systems = std::move(new_disabled_file_systems); -} - bool VirtualFileSystem::SubSystemIsDisabled(const string &name) { + auto registry = file_system_registry.atomic_load(); + auto &disabled_file_systems = registry->disabled_file_systems; return disabled_file_systems.find(name) != disabled_file_systems.end(); } bool VirtualFileSystem::IsDisabledForPath(const string &path) { + auto registry = file_system_registry.atomic_load(); + auto &disabled_file_systems = registry->disabled_file_systems; if (disabled_file_systems.empty()) { return false; } - auto fs = FindFileSystemInternal(path); + auto fs = FindFileSystemInternal(*registry, path); if (!fs) { - fs = default_fs.get(); + fs = registry->default_fs->file_system; } return disabled_file_systems.find(fs->GetName()) != disabled_file_systems.end(); } FileSystem &VirtualFileSystem::FindFileSystem(const string &path, optional_ptr opener) { - return FindFileSystem(path, FileOpener::TryGetDatabase(opener)); + auto registry = file_system_registry.atomic_load(); + return FindFileSystem(registry, path, opener); } -FileSystem &VirtualFileSystem::FindFileSystem(const string &path, optional_ptr db_instance) { - auto fs = FindFileSystemInternal(path); +FileSystem &VirtualFileSystem::FindFileSystem(shared_ptr ®istry, const string &path, + optional_ptr opener) { + auto db_instance = FileOpener::TryGetDatabase(opener); + auto fs = FindFileSystemInternal(*registry, path); if (!fs && db_instance) { string required_extension; @@ -282,9 +362,8 @@ FileSystem &VirtualFileSystem::FindFileSystem(const string &path, optional_ptrExtensionIsLoaded(required_extension)) { - auto &dbconfig = DBConfig::GetConfig(*db_instance); if (!ExtensionHelper::CanAutoloadExtension(required_extension) || - !dbconfig.options.autoload_known_extensions) { + !Settings::Get(*db_instance)) { auto error_message = "File " + path + " requires the extension " + required_extension + " to be loaded"; error_message = ExtensionHelper::AddExtensionInstallHintToErrorMsg(*db_instance, error_message, required_extension); @@ -293,48 +372,35 @@ FileSystem &VirtualFileSystem::FindFileSystem(const string &path, optional_ptrdefault_fs->file_system; } + auto &disabled_file_systems = registry->disabled_file_systems; if (!disabled_file_systems.empty() && disabled_file_systems.find(fs->GetName()) != disabled_file_systems.end()) { throw PermissionException("File system %s has been disabled by configuration", fs->GetName()); } return *fs; } -FileSystem &VirtualFileSystem::FindFileSystem(const string &path) { - auto fs = FindFileSystemInternal(path); - if (!fs) { - fs = default_fs; - } - if (!disabled_file_systems.empty() && disabled_file_systems.find(fs->GetName()) != disabled_file_systems.end()) { - throw PermissionException("File system %s has been disabled by configuration", fs->GetName()); - } - return *fs; -} - -optional_ptr VirtualFileSystem::FindFileSystemInternal(const string &path) { - FileSystem *fs = nullptr; - - for (auto &sub_system : sub_systems) { - if (sub_system->CanHandleFile(path)) { - if (sub_system->IsManuallySet()) { - return *sub_system; +optional_ptr VirtualFileSystem::FindFileSystemInternal(FileSystemRegistry ®istry, const string &path) { + optional_ptr fs; + for (auto &sub_system : registry.sub_systems) { + auto &sub_fs = *sub_system->file_system; + if (sub_fs.CanHandleFile(path)) { + if (sub_fs.IsManuallySet()) { + return sub_fs; } - fs = sub_system.get(); + fs = sub_fs; } } - if (fs) { - return *fs; - } - - // We could use default_fs, that's on the caller - return nullptr; + return fs; } } // namespace duckdb diff --git a/src/duckdb/src/execution/expression_executor.cpp b/src/duckdb/src/execution/expression_executor.cpp index 0278df506..ac803eca2 100644 --- a/src/duckdb/src/execution/expression_executor.cpp +++ b/src/duckdb/src/execution/expression_executor.cpp @@ -11,7 +11,7 @@ namespace duckdb { ExpressionExecutor::ExpressionExecutor(ClientContext &context) : context(&context) { - debug_vector_verification = DBConfig::GetSetting(context); + debug_vector_verification = Settings::Get(context); } ExpressionExecutor::ExpressionExecutor(ClientContext &context, const Expression *expression) diff --git a/src/duckdb/src/execution/expression_executor/execute_function.cpp b/src/duckdb/src/execution/expression_executor/execute_function.cpp index d3610dae2..4b3272edd 100644 --- a/src/duckdb/src/execution/expression_executor/execute_function.cpp +++ b/src/duckdb/src/execution/expression_executor/execute_function.cpp @@ -116,6 +116,16 @@ bool ExecuteFunctionState::TryExecuteDictionaryExpression(const BoundFunctionExp return true; } +void ExecuteFunctionState::ResetDictionaryStates() { + // Clear the cached dictionary information + current_input_dictionary_id.clear(); + output_dictionary.reset(); + + for (const auto &child_state : child_states) { + child_state->ResetDictionaryStates(); + } +} + unique_ptr ExpressionExecutor::InitializeState(const BoundFunctionExpression &expr, ExpressionExecutorState &root) { auto result = make_uniq(expr, root); diff --git a/src/duckdb/src/execution/expression_executor/execute_operator.cpp b/src/duckdb/src/execution/expression_executor/execute_operator.cpp index 527178d36..8d3cfee46 100644 --- a/src/duckdb/src/execution/expression_executor/execute_operator.cpp +++ b/src/duckdb/src/execution/expression_executor/execute_operator.cpp @@ -133,12 +133,19 @@ void ExpressionExecutor::Execute(const BoundOperatorExpression &expr, Expression throw; } } + + // On error, evaluate per row SelectionVector selvec(1); DataChunk intermediate; intermediate.Initialize(GetAllocator(), {result.GetType()}, 1); for (idx_t i = 0; i < count; i++) { intermediate.Reset(); intermediate.SetCardinality(1); + + // Make sure to clear any dictionary states in the child expression, so that it actually + // gets executed anew for every row + child_state.ResetDictionaryStates(); + selvec.set_index(0, sel ? sel->get_index(i) : i); Value val(result.GetType()); try { diff --git a/src/duckdb/src/execution/expression_executor_state.cpp b/src/duckdb/src/execution/expression_executor_state.cpp index 070a399db..fcac6065b 100644 --- a/src/duckdb/src/execution/expression_executor_state.cpp +++ b/src/duckdb/src/execution/expression_executor_state.cpp @@ -52,6 +52,12 @@ void ExpressionState::Verify(ExpressionExecutorState &root_executor) { } } +void ExpressionState::ResetDictionaryStates() { + for (const auto &child : child_states) { + child->ResetDictionaryStates(); + } +} + void ExpressionExecutorState::Verify() { D_ASSERT(executor); root_state->Verify(*this); diff --git a/src/duckdb/src/execution/index/art/art.cpp b/src/duckdb/src/execution/index/art/art.cpp index 800135f0d..e6b5a0bb7 100644 --- a/src/duckdb/src/execution/index/art/art.cpp +++ b/src/duckdb/src/execution/index/art/art.cpp @@ -23,6 +23,7 @@ #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/storage/arena_allocator.hpp" #include "duckdb/storage/metadata/metadata_reader.hpp" +#include "duckdb/storage/table/append_state.hpp" #include "duckdb/storage/table/scan_state.hpp" #include "duckdb/storage/table_io_manager.hpp" @@ -49,7 +50,7 @@ ART::ART(const string &name, const IndexConstraintType index_constraint_type, co const shared_ptr, ALLOCATOR_COUNT>> &allocators_ptr, const IndexStorageInfo &info) : BoundIndex(name, ART::TYPE_NAME, index_constraint_type, column_ids, table_io_manager, unbound_expressions, db), - allocators(allocators_ptr), owns_data(false), verify_max_key_len(false) { + allocators(allocators_ptr), owns_data(false) { // FIXME: Use the new byte representation function to support nested types. for (idx_t i = 0; i < types.size(); i++) { switch (types[i]) { @@ -73,12 +74,6 @@ ART::ART(const string &name, const IndexConstraintType index_constraint_type, co } } - if (types.size() > 1) { - verify_max_key_len = true; - } else if (types[0] == PhysicalType::VARCHAR) { - verify_max_key_len = true; - } - // Initialize the allocators. SetPrefixCount(info); if (!allocators) { @@ -393,25 +388,11 @@ void GenerateKeysInternal(ArenaAllocator &allocator, DataChunk &input, unsafe_ve template <> void ART::GenerateKeys<>(ArenaAllocator &allocator, DataChunk &input, unsafe_vector &keys) { GenerateKeysInternal(allocator, input, keys); - if (!verify_max_key_len) { - return; - } - auto max_len = MAX_KEY_LEN * idx_t(prefix_count); - for (idx_t i = 0; i < input.size(); i++) { - keys[i].VerifyKeyLength(max_len); - } } template <> void ART::GenerateKeys(ArenaAllocator &allocator, DataChunk &input, unsafe_vector &keys) { GenerateKeysInternal(allocator, input, keys); - if (!verify_max_key_len) { - return; - } - auto max_len = MAX_KEY_LEN * idx_t(prefix_count); - for (idx_t i = 0; i < input.size(); i++) { - keys[i].VerifyKeyLength(max_len); - } } void ART::GenerateKeyVectors(ArenaAllocator &allocator, DataChunk &input, Vector &row_ids, unsafe_vector &keys, @@ -444,7 +425,8 @@ ARTConflictType ART::Build(unsafe_vector &keys, unsafe_vector &r Iterator it(*this); it.FindMinimum(tree); ARTKey empty_key = ARTKey(); - it.Scan(empty_key, NumericLimits().Maximum(), row_ids_debug, false); + RowIdSetOutput output(row_ids_debug, NumericLimits().Maximum()); + it.Scan(empty_key, output, false); D_ASSERT(row_count == row_ids_debug.size()); #endif @@ -469,6 +451,13 @@ ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, IndexAppe unsafe_vector row_id_keys(row_count); GenerateKeyVectors(arena, chunk, row_ids, keys, row_id_keys); + return InsertKeys(arena, keys, row_id_keys, row_count, DeleteIndexInfo(info.delete_indexes), info.append_mode, + &chunk); +} + +ErrorData ART::InsertKeys(ArenaAllocator &arena, unsafe_vector &keys, unsafe_vector &row_id_keys, + idx_t row_count, const DeleteIndexInfo &delete_info, IndexAppendMode append_mode, + optional_ptr chunk) { auto conflict_type = ARTConflictType::NO_CONFLICT; optional_idx conflict_idx; auto was_empty = !tree.HasMetadata(); @@ -479,7 +468,7 @@ ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, IndexAppe continue; } conflict_type = ARTOperator::Insert(arena, *this, tree, keys[i], 0, row_id_keys[i], GateStatus::GATE_NOT_SET, - DeleteIndexInfo(info.delete_indexes), info.append_mode); + delete_info, append_mode); if (conflict_type != ARTConflictType::NO_CONFLICT) { conflict_idx = i; break; @@ -504,12 +493,14 @@ ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, IndexAppe } if (conflict_type == ARTConflictType::TRANSACTION) { - auto msg = AppendRowError(chunk, conflict_idx.GetIndex()); + // chunk is only null when called from MergeCheckpointDeltas. + auto msg = chunk ? AppendRowError(*chunk, conflict_idx.GetIndex()) : string("???"); return ErrorData(TransactionException("write-write conflict on key: \"%s\"", msg)); } if (conflict_type == ARTConflictType::CONSTRAINT) { - auto msg = AppendRowError(chunk, conflict_idx.GetIndex()); + // chunk is only null when called from MergeCheckpointDeltas. + auto msg = chunk ? AppendRowError(*chunk, conflict_idx.GetIndex()) : string("???"); return ErrorData(ConstraintException("PRIMARY KEY or UNIQUE constraint violation: duplicate key \"%s\"", msg)); } @@ -582,6 +573,11 @@ idx_t ART::TryDelete(IndexLock &state, DataChunk &entries, Vector &row_ids, opti unsafe_vector row_id_keys(row_count); GenerateKeyVectors(allocator, expr_chunk, row_ids, keys, row_id_keys); + return DeleteKeys(keys, row_id_keys, row_count, deleted_sel, non_deleted_sel); +} + +idx_t ART::DeleteKeys(unsafe_vector &keys, unsafe_vector &row_id_keys, idx_t row_count, + optional_ptr deleted_sel, optional_ptr non_deleted_sel) { idx_t delete_count = 0; for (idx_t i = 0; i < row_count; i++) { bool deleted = true; @@ -630,7 +626,8 @@ bool ART::FullScan(idx_t max_count, set &row_ids) { Iterator it(*this); it.FindMinimum(tree); ARTKey empty_key = ARTKey(); - return it.Scan(empty_key, max_count, row_ids, false); + RowIdSetOutput output(row_ids, max_count); + return it.Scan(empty_key, output, false) == ARTScanResult::COMPLETED; } bool ART::SearchEqual(ARTKey &key, idx_t max_count, set &row_ids) { @@ -642,7 +639,8 @@ bool ART::SearchEqual(ARTKey &key, idx_t max_count, set &row_ids) { Iterator it(*this); it.FindMinimum(*leaf); ARTKey empty_key = ARTKey(); - return it.Scan(empty_key, max_count, row_ids, false); + RowIdSetOutput output(row_ids, max_count); + return it.Scan(empty_key, output, false) == ARTScanResult::COMPLETED; } bool ART::SearchGreater(ARTKey &key, bool equal, idx_t max_count, set &row_ids) { @@ -660,7 +658,8 @@ bool ART::SearchGreater(ARTKey &key, bool equal, idx_t max_count, set &ro // We continue the scan. We do not check the bounds as any value following this value is // greater and satisfies our predicate. - return it.Scan(ARTKey(), max_count, row_ids, false); + RowIdSetOutput output(row_ids, max_count); + return it.Scan(ARTKey(), output, false) == ARTScanResult::COMPLETED; } bool ART::SearchLess(ARTKey &upper_bound, bool equal, idx_t max_count, set &row_ids) { @@ -678,7 +677,8 @@ bool ART::SearchLess(ARTKey &upper_bound, bool equal, idx_t max_count, set &row_ids) { @@ -705,8 +706,6 @@ bool ART::Scan(IndexScanState &state, const idx_t max_count, set &row_ids D_ASSERT(scan_state.values[0].type().InternalType() == types[0]); ArenaAllocator arena_allocator(Allocator::Get(db)); auto key = ARTKey::CreateKey(arena_allocator, types[0], scan_state.values[0]); - auto max_len = MAX_KEY_LEN * prefix_count; - key.VerifyKeyLength(max_len); lock_guard l(lock); if (scan_state.values[1].IsNull()) { @@ -730,7 +729,6 @@ bool ART::Scan(IndexScanState &state, const idx_t max_count, set &row_ids // Two predicates. D_ASSERT(scan_state.values[1].type().InternalType() == types[0]); auto upper_bound = ARTKey::CreateKey(arena_allocator, types[0], scan_state.values[1]); - upper_bound.VerifyKeyLength(max_len); bool left_equal = scan_state.expressions[0] == ExpressionType ::COMPARE_GREATERTHANOREQUALTO; bool right_equal = scan_state.expressions[1] == ExpressionType ::COMPARE_LESSTHANOREQUALTO; @@ -836,8 +834,9 @@ void ART::VerifyLeaf(const Node &leaf, const ARTKey &key, DeleteIndexInfo delete it.FindMinimum(leaf); ARTKey empty_key = ARTKey(); set row_ids; - auto success = it.Scan(empty_key, 2, row_ids, false); - if (!success || row_ids.size() != 2) { + RowIdSetOutput output(row_ids, 2); + auto result = it.Scan(empty_key, output, false); + if (result != ARTScanResult::COMPLETED || row_ids.size() != 2) { throw InternalException("VerifyLeaf expects exactly two row IDs to be scanned"); } @@ -1032,9 +1031,6 @@ void ART::Deserialize(const BlockPointer &pointer) { } void ART::SetPrefixCount(const IndexStorageInfo &info) { - auto numeric_max = NumericLimits().Maximum(); - auto max_aligned = AlignValueFloor(numeric_max - Prefix::METADATA_SIZE); - if (info.IsValid() && info.root_block_ptr.IsValid()) { prefix_count = Prefix::DEPRECATED_COUNT; return; @@ -1051,13 +1047,18 @@ void ART::SetPrefixCount(const IndexStorageInfo &info) { compound_size += GetTypeIdSize(type); } - auto aligned = AlignValue(compound_size) - 1; - if (aligned > NumericCast(max_aligned)) { - prefix_count = max_aligned; - return; - } + // Get the maximum possible prefix size. + // Minus one to index the prefix count (last byte). + auto numeric_max = NumericLimits().Maximum(); + uint8_t max_aligned = AlignValueFloor(numeric_max - Prefix::METADATA_SIZE) - 1; + + // Ceiling of compound size, + // minus one to index the prefix count (last byte). + idx_t key_aligned = AlignValue(compound_size) - 1; - prefix_count = NumericCast(aligned); + // Set the prefix size to the maximum of the (compound) key size and the maximum prefix size. + bool exceeds_max = key_aligned > NumericCast(max_aligned); + prefix_count = exceeds_max ? max_aligned : NumericCast(key_aligned); } idx_t ART::GetInMemorySize(IndexLock &index_lock) { @@ -1205,8 +1206,8 @@ void ART::InitializeMerge(Node &node, unsafe_vector &upper_bounds) { scanner.Scan(handler); } -bool ART::MergeIndexes(IndexLock &state, BoundIndex &other_index) { - auto &other_art = other_index.Cast(); +bool ART::MergeIndexes(IndexLock &state, BoundIndex &source_index) { + auto &other_art = source_index.Cast(); if (!other_art.tree.HasMetadata()) { return true; } @@ -1242,6 +1243,88 @@ bool ART::MergeIndexes(IndexLock &state, BoundIndex &other_index) { return true; } +// FIXME : Make this a more efficient structural tree removal merge +// Right now this is only used in MergeCheckpointDeltas to avoid having to do a table scan. +void ART::RemovalMerge(IndexLock &state, BoundIndex &source_index) { + auto &source = source_index.Cast(); + if (!source.tree.HasMetadata()) { + return; + } + + ArenaAllocator arena(BufferAllocator::Get(db)); + idx_t scan_count = 0; + idx_t delete_count = 0; + + Iterator it(source); + it.FindMinimum(source.tree); + + unsafe_vector keys(STANDARD_VECTOR_SIZE); + unsafe_vector row_id_keys(STANDARD_VECTOR_SIZE); + ARTKey empty_key = ARTKey(); + + KeyRowIdOutput output(arena, keys, row_id_keys, STANDARD_VECTOR_SIZE); + ARTScanResult result; + do { + output.Reset(); + result = it.Scan(empty_key, output, false); + if (output.Count() > 0) { + scan_count += output.Count(); + delete_count += DeleteKeys(keys, row_id_keys, output.Count()); + } + } while (result == ARTScanResult::PAUSED); + + if (delete_count != scan_count) { + throw InternalException("Failed to remove all rows while merging checkpoint deltas - " + "this signifies a bug or broken index"); + } +} + +void ART::RemovalMerge(BoundIndex &source_index) { + IndexLock state; + InitializeLock(state); + RemovalMerge(state, source_index); +} + +// FIXME: We already have a structural tree merge, this only exists right now since the structural merge doesn't +// handle deprecated leaves. This is being used in merging checkpoint deltas, to avoid a more inefficient table scan. +// Once the structural merge adds support for deprecated leaves, we can replace the calls of this function with that. +ErrorData ART::InsertMerge(IndexLock &state, BoundIndex &source_index, IndexAppendMode append_mode) { + auto &source = source_index.Cast(); + if (!source.tree.HasMetadata()) { + return ErrorData(); + } + + ArenaAllocator arena(BufferAllocator::Get(db)); + + Iterator it(source); + it.FindMinimum(source.tree); + + unsafe_vector keys(STANDARD_VECTOR_SIZE); + unsafe_vector row_id_keys(STANDARD_VECTOR_SIZE); + ARTKey empty_key = ARTKey(); + + KeyRowIdOutput output(arena, keys, row_id_keys, STANDARD_VECTOR_SIZE); + ARTScanResult result; + do { + output.Reset(); + result = it.Scan(empty_key, output, false); + if (output.Count() > 0) { + auto error = InsertKeys(arena, keys, row_id_keys, output.Count(), DeleteIndexInfo(), append_mode); + if (error.HasError()) { + return error; + } + } + } while (result == ARTScanResult::PAUSED); + + return ErrorData(); +} + +ErrorData ART::InsertMerge(BoundIndex &source_index, IndexAppendMode append_mode) { + IndexLock state; + InitializeLock(state); + return InsertMerge(state, source_index, append_mode); +} + //===--------------------------------------------------------------------===// // Verification //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/execution/index/art/art_key.cpp b/src/duckdb/src/execution/index/art/art_key.cpp index 7a6df37ce..0d380701f 100644 --- a/src/duckdb/src/execution/index/art/art_key.cpp +++ b/src/duckdb/src/execution/index/art/art_key.cpp @@ -16,13 +16,6 @@ ARTKey::ARTKey(ArenaAllocator &allocator, idx_t len) : len(len) { data = allocator.Allocate(len); } -void ARTKey::VerifyKeyLength(const idx_t max_len) const { - if (len > max_len) { - throw InvalidInputException("key size of %d bytes exceeds the maximum size of %d bytes for this ART", len, - max_len); - } -} - template <> ARTKey ARTKey::CreateARTKey(ArenaAllocator &allocator, string_t value) { auto string_data = const_data_ptr_cast(value.GetData()); diff --git a/src/duckdb/src/execution/index/art/iterator.cpp b/src/duckdb/src/execution/index/art/iterator.cpp index 604704bc6..b47e41933 100644 --- a/src/duckdb/src/execution/index/art/iterator.cpp +++ b/src/duckdb/src/execution/index/art/iterator.cpp @@ -42,46 +42,77 @@ bool IteratorKey::GreaterThan(const ARTKey &key, const bool equal, const uint8_t // Iterator //===--------------------------------------------------------------------===// -bool Iterator::Scan(const ARTKey &upper_bound, const idx_t max_count, set &row_ids, const bool equal) { +template +ARTScanResult Iterator::Scan(const ARTKey &upper_bound, Output &output, bool equal) { bool has_next; do { // An empty upper bound indicates that no upper bound exists. if (!upper_bound.Empty()) { if (status == GateStatus::GATE_NOT_SET || entered_nested_leaf) { if (current_key.GreaterThan(upper_bound, equal, nested_depth)) { - return true; + return ARTScanResult::COMPLETED; } } } + // Set the current key in the output policy. + D_ASSERT(current_key.Size() >= nested_depth); + auto key_len = current_key.Size() - nested_depth; + output.SetKey(current_key, key_len); + switch (last_leaf.GetType()) { - case NType::LEAF_INLINED: - if (row_ids.size() + 1 > max_count) { - return false; + case NType::LEAF_INLINED: { + if (output.IsFull()) { + return ARTScanResult::PAUSED; } - row_ids.insert(last_leaf.GetRowId()); + output.Add(last_leaf.GetRowId()); break; - case NType::LEAF: - if (!Leaf::DeprecatedGetRowIds(art, last_leaf, row_ids, max_count)) { - return false; + } + case NType::LEAF: { + D_ASSERT(nested_depth == 0); + if (!resume_state.has_cached_row_ids) { + resume_state.cached_row_ids.clear(); + Leaf::DeprecatedGetRowIds(art, last_leaf, resume_state.cached_row_ids, NumericLimits::Maximum()); + resume_state.cached_row_ids_it = resume_state.cached_row_ids.begin(); + resume_state.has_cached_row_ids = true; } + // Try to output the next entry in the deprecated leaf chain. + while (resume_state.cached_row_ids_it != resume_state.cached_row_ids.end()) { + if (output.IsFull()) { + // If we pause here, then scanning will resume at cached_row_ids_it. + return ARTScanResult::PAUSED; + } + output.Add(*resume_state.cached_row_ids_it); + ++resume_state.cached_row_ids_it; + } + resume_state.has_cached_row_ids = false; break; + } case NType::NODE_7_LEAF: case NType::NODE_15_LEAF: case NType::NODE_256_LEAF: { - uint8_t byte = 0; - while (last_leaf.GetNextByte(art, byte)) { - if (row_ids.size() + 1 > max_count) { - return false; + // If we haven't traversed this leaf yet, set nested_started to true (allows us to pick up iteration again + // in case we fill the output with capacity. + if (!resume_state.nested_started) { + resume_state.nested_byte = 0; + resume_state.nested_started = true; + } + // Try to output the next inlined leaf. + while (last_leaf.GetNextByte(art, resume_state.nested_byte)) { + if (output.IsFull()) { + // If we pause here, then scanning will resume at nested_byte in the current leaf. + return ARTScanResult::PAUSED; } - row_id[ROW_ID_SIZE - 1] = byte; - ARTKey key(&row_id[0], ROW_ID_SIZE); - row_ids.insert(key.GetRowId()); - if (byte == NumericLimits::Maximum()) { + row_id[ROW_ID_SIZE - 1] = resume_state.nested_byte; + ARTKey rid_key(&row_id[0], ROW_ID_SIZE); + output.Add(rid_key.GetRowId()); + + if (resume_state.nested_byte == NumericLimits::Maximum()) { break; } - byte++; + resume_state.nested_byte++; } + resume_state.nested_started = false; break; } default: @@ -91,9 +122,13 @@ bool Iterator::Scan(const ARTKey &upper_bound, const idx_t max_count, set entered_nested_leaf = false; has_next = Next(); } while (has_next); - return true; + return ARTScanResult::COMPLETED; } +// Explicit template instantiations for the two output policies. +template ARTScanResult Iterator::Scan(const ARTKey &, RowIdSetOutput &, bool); +template ARTScanResult Iterator::Scan(const ARTKey &, KeyRowIdOutput &, bool); + void Iterator::FindMinimum(const Node &node) { reference ref(node); diff --git a/src/duckdb/src/execution/index/art/leaf.cpp b/src/duckdb/src/execution/index/art/leaf.cpp index 4895f996b..8ce72df70 100644 --- a/src/duckdb/src/execution/index/art/leaf.cpp +++ b/src/duckdb/src/execution/index/art/leaf.cpp @@ -115,7 +115,8 @@ void Leaf::TransformToDeprecated(ART &art, Node &node) { Iterator it(art); it.FindMinimum(node); ARTKey empty_key = ARTKey(); - it.Scan(empty_key, NumericLimits().Maximum(), row_ids, false); + RowIdSetOutput output(row_ids, NumericLimits().Maximum()); + it.Scan(empty_key, output, false); Node::FreeTree(art, node); D_ASSERT(row_ids.size() > 1); diff --git a/src/duckdb/src/execution/index/art/node.cpp b/src/duckdb/src/execution/index/art/node.cpp index fec9c9c70..917504777 100644 --- a/src/duckdb/src/execution/index/art/node.cpp +++ b/src/duckdb/src/execution/index/art/node.cpp @@ -359,32 +359,57 @@ bool Node::IsAnyLeaf() const { // TransformToDeprecated //===--------------------------------------------------------------------===// +template +static void TransformToDeprecatedPushChildren(ART &art, Node &node, NType type, vector> &stack) { + auto ptr = Node::InMemoryRef(art, node, type); + if (ptr) { + NODE::Iterator(*ptr, [&](Node &child) { stack.emplace_back(child); }); + } +} + void Node::TransformToDeprecated(ART &art, Node &node, TransformToDeprecatedState &state) { - D_ASSERT(node.HasMetadata()); + vector> stack; + stack.emplace_back(node); - if (node.GetGateStatus() == GateStatus::GATE_SET) { - D_ASSERT(node.GetType() != NType::LEAF_INLINED); - return Leaf::TransformToDeprecated(art, node); - } + while (!stack.empty()) { + Node ¤t = stack.back().get(); + stack.pop_back(); - auto type = node.GetType(); - switch (type) { - case NType::PREFIX: - return PrefixHandle::TransformToDeprecated(art, node, state); - case NType::LEAF_INLINED: - return; - case NType::LEAF: - return; - case NType::NODE_4: - return TransformToDeprecatedInternal(art, InMemoryRef(art, node, type), state); - case NType::NODE_16: - return TransformToDeprecatedInternal(art, InMemoryRef(art, node, type), state); - case NType::NODE_48: - return TransformToDeprecatedInternal(art, InMemoryRef(art, node, type), state); - case NType::NODE_256: - return TransformToDeprecatedInternal(art, InMemoryRef(art, node, type), state); - default: - throw InternalException("invalid node type for TransformToDeprecated: %d", type); + D_ASSERT(current.HasMetadata()); + + if (current.GetGateStatus() == GateStatus::GATE_SET) { + D_ASSERT(current.GetType() != NType::LEAF_INLINED); + Leaf::TransformToDeprecated(art, current); + continue; + } + + auto type = current.GetType(); + switch (type) { + case NType::PREFIX: { + auto child = PrefixHandle::TransformToDeprecated(art, current, state); + if (child) { + stack.emplace_back(*child); + } + break; + } + case NType::LEAF_INLINED: + case NType::LEAF: + break; + case NType::NODE_4: + TransformToDeprecatedPushChildren(art, current, type, stack); + break; + case NType::NODE_16: + TransformToDeprecatedPushChildren(art, current, type, stack); + break; + case NType::NODE_48: + TransformToDeprecatedPushChildren(art, current, type, stack); + break; + case NType::NODE_256: + TransformToDeprecatedPushChildren(art, current, type, stack); + break; + default: + throw InternalException("invalid node type for TransformToDeprecated: %d", type); + } } } diff --git a/src/duckdb/src/execution/index/art/prefix_handle.cpp b/src/duckdb/src/execution/index/art/prefix_handle.cpp index a8d954988..b52a5690e 100644 --- a/src/duckdb/src/execution/index/art/prefix_handle.cpp +++ b/src/duckdb/src/execution/index/art/prefix_handle.cpp @@ -48,19 +48,19 @@ PrefixHandle PrefixHandle::NewDeprecated(FixedSizeAllocator &allocator, Node &no return handle; } -void PrefixHandle::TransformToDeprecated(ART &art, Node &node, TransformToDeprecatedState &state) { +optional_ptr PrefixHandle::TransformToDeprecated(ART &art, Node &node, TransformToDeprecatedState &state) { // Early-out, if we do not need any transformations. if (!state.HasAllocator()) { reference ref(node); while (ref.get().GetType() == PREFIX && ref.get().GetGateStatus() == GateStatus::GATE_NOT_SET) { auto &alloc = Node::GetAllocator(art, PREFIX); if (!alloc.LoadedFromStorage(ref)) { - return; + return nullptr; } PrefixHandle handle(art, ref); ref = *handle.child; } - return Node::TransformToDeprecated(art, ref, state); + return ref.get(); } // We need to create a new prefix (chain) in the deprecated format. @@ -72,7 +72,7 @@ void PrefixHandle::TransformToDeprecated(ART &art, Node &node, TransformToDeprec while (current_node.GetType() == PREFIX && current_node.GetGateStatus() == GateStatus::GATE_NOT_SET) { auto &alloc = Node::GetAllocator(art, PREFIX); if (!alloc.LoadedFromStorage(current_node)) { - return; + return nullptr; } PrefixHandle current_handle(art, current_node); @@ -87,7 +87,7 @@ void PrefixHandle::TransformToDeprecated(ART &art, Node &node, TransformToDeprec } node = new_node; - return Node::TransformToDeprecated(art, *new_handle.child, state); + return new_handle.child; } PrefixHandle PrefixHandle::TransformToDeprecatedAppend(ART &art, FixedSizeAllocator &allocator, const uint8_t byte) { diff --git a/src/duckdb/src/execution/join_hashtable.cpp b/src/duckdb/src/execution/join_hashtable.cpp index ef2fe68ac..82d58290d 100644 --- a/src/duckdb/src/execution/join_hashtable.cpp +++ b/src/duckdb/src/execution/join_hashtable.cpp @@ -1,13 +1,14 @@ #include "duckdb/execution/join_hashtable.hpp" +#include "duckdb/common/enums/join_type.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/radix_partitioning.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/execution/ht_entry.hpp" +#include "duckdb/logging/log_manager.hpp" #include "duckdb/main/client_context.hpp" -#include "duckdb/storage/buffer_manager.hpp" #include "duckdb/main/settings.hpp" -#include "duckdb/logging/log_manager.hpp" +#include "duckdb/storage/buffer_manager.hpp" namespace duckdb { @@ -109,7 +110,7 @@ JoinHashTable::JoinHashTable(ClientContext &context_p, const PhysicalOperator &o memset(dead_end.get(), 0, layout_ptr->GetRowWidth()); if (join_type == JoinType::SINGLE) { - single_join_error_on_multiple_rows = DBConfig::GetSetting(context); + single_join_error_on_multiple_rows = Settings::Get(context); } if (conditions.size() == 1 && @@ -1136,25 +1137,35 @@ void ScanStructure::NextRightSemiOrAntiJoin(DataChunk &keys) { // resolve the equality_predicates for this set of keys idx_t result_count = ResolvePredicates(keys, chain_match_sel_vector, nullptr); - // for each match, fully follow the chain - for (idx_t i = 0; i < result_count; i++) { - const auto idx = chain_match_sel_vector.get_index(i); - auto &ptr = ptrs[idx]; - if (Load(ptr + ht.tuple_size)) { // Early out: chain has been fully marked as found before - ptr = ht.dead_end.get(); - continue; - } + if (ht.non_equality_predicates.empty()) { + // we only have equality predicates - the match is found for the entire chain + for (idx_t i = 0; i < result_count; i++) { + const auto idx = chain_match_sel_vector.get_index(i); + auto &ptr = ptrs[idx]; + if (Load(ptr + ht.tuple_size)) { // Early out: chain has been fully marked as found before + ptr = ht.dead_end.get(); + continue; + } - // Fully mark chain as found - while (true) { - // NOTE: threadsan reports this as a data race because this can be set concurrently by separate threads - // Technically it is, but it does not matter, since the only value that can be written is "true" - Store(true, ptr + ht.tuple_size); - auto next_ptr = LoadPointer(ptr + ht.pointer_offset); - if (!next_ptr) { - break; + // Fully mark chain as found + while (true) { + // NOTE: threadsan reports this as a data race because this can be set concurrently by separate + // threads Technically it is, but it does not matter, since the only value that can be written is + // "true" + Store(true, ptr + ht.tuple_size); + auto next_ptr = LoadPointer(ptr + ht.pointer_offset); + if (!next_ptr) { + break; + } + ptr = next_ptr; } - ptr = next_ptr; + } + } else { + // we have non-equality predicates - we need to evaluate the join condition for every row + // for each match found in the current pass - mark the match as found + for (idx_t i = 0; i < result_count; i++) { + auto idx = chain_match_sel_vector.get_index(i); + Store(true, ptrs[idx] + ht.tuple_size); } } diff --git a/src/duckdb/src/execution/operator/aggregate/physical_streaming_window.cpp b/src/duckdb/src/execution/operator/aggregate/physical_streaming_window.cpp index 097994855..3f7082de4 100644 --- a/src/duckdb/src/execution/operator/aggregate/physical_streaming_window.cpp +++ b/src/duckdb/src/execution/operator/aggregate/physical_streaming_window.cpp @@ -185,16 +185,16 @@ class StreamingWindowState : public OperatorState { // Special case when we have buffered enough values for the output if (count < buffered) { // Shift down incomplete buffers - // Copy prev[buffered-count, buffered] => temp[0, count] + // Copy prev[count, buffered] => temp[0, buffered-count] source_count = buffered - count; FlatVector::Validity(temp).Reset(); - VectorOperations::Copy(prev, temp, buffered, source_count, 0); + VectorOperations::Copy(prev, temp, buffered, count, 0); - // Copy temp[0, count] => prev[0, count] + // Copy temp[0, buffered-count] => prev[0, buffered-count] FlatVector::Validity(prev).Reset(); - VectorOperations::Copy(temp, prev, count, 0, 0); - // Copy curr[0, buffered-count] => prev[count, buffered] - VectorOperations::Copy(curr, prev, source_count, 0, count); + VectorOperations::Copy(temp, prev, source_count, 0, 0); + // Copy curr[0, count] => prev[buffered-count, buffered] + VectorOperations::Copy(curr, prev, count, 0, source_count); } else { // Copy input values beyond what we have buffered source_count = count - buffered; diff --git a/src/duckdb/src/execution/operator/aggregate/physical_window.cpp b/src/duckdb/src/execution/operator/aggregate/physical_window.cpp index 5e23c8cd3..67a9bf5e2 100644 --- a/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +++ b/src/duckdb/src/execution/operator/aggregate/physical_window.cpp @@ -280,7 +280,7 @@ static unique_ptr WindowExecutorFactory(BoundWindowExpression &w case ExpressionType::WINDOW_LAG: return make_uniq(wexpr, shared); case ExpressionType::WINDOW_FILL: - return make_uniq(wexpr, shared); + return make_uniq(wexpr, client, shared); case ExpressionType::WINDOW_FIRST_VALUE: return make_uniq(wexpr, shared); case ExpressionType::WINDOW_LAST_VALUE: @@ -298,7 +298,7 @@ WindowGlobalSinkState::WindowGlobalSinkState(const PhysicalWindow &op, ClientCon D_ASSERT(op.select_list[op.order_idx]->GetExpressionClass() == ExpressionClass::BOUND_WINDOW); auto &wexpr = op.select_list[op.order_idx]->Cast(); - const auto mode = DBConfig::GetSetting(client); + const auto mode = Settings::Get(client); for (idx_t expr_idx = 0; expr_idx < op.select_list.size(); ++expr_idx) { D_ASSERT(op.select_list[expr_idx]->GetExpressionClass() == ExpressionClass::BOUND_WINDOW); auto &wexpr = op.select_list[expr_idx]->Cast(); diff --git a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer.cpp b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer.cpp index 5c09dd0d6..1ee13e69a 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer.cpp @@ -69,7 +69,7 @@ void CSVBuffer::Reload(CSVFileHandle &file_handle) { shared_ptr CSVBuffer::Pin(CSVFileHandle &file_handle, bool &has_seeked) { auto &buffer_manager = BufferManager::GetBufferManager(context); - if (!block || (!is_pipe && block->IsUnloaded())) { + if (!block || (!is_pipe && block->GetMemory().IsUnloaded())) { // We have to reload it from disk block = nullptr; Reload(file_handle); diff --git a/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp b/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp index 75a680b3b..bd71f73ca 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp @@ -742,7 +742,7 @@ void CSVReaderOptions::ParseOption(ClientContext &context, const string &key, co sql_type_list.reserve(sql_type_names.size()); for (auto &sql_type : sql_type_names) { auto def_type = TransformStringToLogicalType(sql_type, context); - if (def_type.id() == LogicalTypeId::USER) { + if (def_type.id() == LogicalTypeId::UNBOUND) { throw BinderException("Unrecognized type \"%s\" for read_csv %s definition", sql_type, key); } sql_type_list.push_back(std::move(def_type)); diff --git a/src/duckdb/src/execution/operator/helper/physical_explain_analyze.cpp b/src/duckdb/src/execution/operator/helper/physical_explain_analyze.cpp index 1404ea0e9..c9b986967 100644 --- a/src/duckdb/src/execution/operator/helper/physical_explain_analyze.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_explain_analyze.cpp @@ -21,6 +21,7 @@ SinkFinalizeType PhysicalExplainAnalyze::Finalize(Pipeline &pipeline, Event &eve OperatorSinkFinalizeInput &input) const { auto &gstate = input.global_state.Cast(); auto &profiler = QueryProfiler::Get(context); + profiler.FinalizeMetrics(); gstate.analyzed_plan = profiler.ToString(format); return SinkFinalizeType::READY; } diff --git a/src/duckdb/src/execution/operator/helper/physical_reset.cpp b/src/duckdb/src/execution/operator/helper/physical_reset.cpp index 4402d6e3e..d549d633b 100644 --- a/src/duckdb/src/execution/operator/helper/physical_reset.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_reset.cpp @@ -1,4 +1,5 @@ #include "duckdb/execution/operator/helper/physical_reset.hpp" +#include "duckdb/execution/operator/helper/physical_set.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/main/database.hpp" @@ -12,10 +13,11 @@ void PhysicalReset::ResetExtensionVariable(ExecutionContext &context, DBConfig & extension_option.set_function(context.client, scope, extension_option.default_value); } if (scope == SetScope::GLOBAL) { - config.ResetOption(name); + config.ResetOption(extension_option); } else { auto &client_config = ClientConfig::GetConfig(context.client); - client_config.set_variables[name.ToStdString()] = extension_option.default_value; + auto setting_index = extension_option.setting_index.GetIndex(); + client_config.user_settings.SetUserSetting(setting_index, extension_option.default_value); } } @@ -29,32 +31,21 @@ SourceResultType PhysicalReset::GetDataInternal(ExecutionContext &context, DataC auto &config = DBConfig::GetConfig(context.client); config.CheckLock(name); auto option = DBConfig::GetOptionByName(name); - if (!option) { // check if this is an extra extension variable - auto entry = config.extension_parameters.find(name.ToStdString()); - if (entry == config.extension_parameters.end()) { + ExtensionOption extension_option; + if (!config.TryGetExtensionOption(name, extension_option)) { auto extension_name = Catalog::AutoloadExtensionByConfigName(context.client, name); - entry = config.extension_parameters.find(name.ToStdString()); - if (entry == config.extension_parameters.end()) { + if (!config.TryGetExtensionOption(name, extension_option)) { throw InvalidInputException("Extension parameter %s was not found after autoloading", name); } } - ResetExtensionVariable(context, config, entry->second); + ResetExtensionVariable(context, config, extension_option); return SourceResultType::FINISHED; } // Transform scope - SetScope variable_scope = scope; - if (variable_scope == SetScope::AUTOMATIC) { - if (option->set_local) { - variable_scope = SetScope::SESSION; - } else if (option->set_global) { - variable_scope = SetScope::GLOBAL; - } else { - variable_scope = option->default_scope; - } - } + SetScope variable_scope = PhysicalSet::GetSettingScope(*option, scope); if (option->default_value) { if (option->set_callback) { @@ -63,11 +54,12 @@ SourceResultType PhysicalReset::GetDataInternal(ExecutionContext &context, DataC Value reset_val = Value(option->default_value).CastAs(context.client, parameter_type); option->set_callback(info, reset_val); } + auto setting_index = option->setting_idx.GetIndex(); if (variable_scope == SetScope::SESSION) { auto &client_config = ClientConfig::GetConfig(context.client); - client_config.set_variables.erase(option->name); + client_config.user_settings.ClearSetting(setting_index); } else { - config.ResetGenericOption(option->name); + config.ResetGenericOption(setting_index); } return SourceResultType::FINISHED; } diff --git a/src/duckdb/src/execution/operator/helper/physical_set.cpp b/src/duckdb/src/execution/operator/helper/physical_set.cpp index 82f505113..c9d65340e 100644 --- a/src/duckdb/src/execution/operator/helper/physical_set.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_set.cpp @@ -6,13 +6,13 @@ namespace duckdb { -void PhysicalSet::SetGenericVariable(ClientContext &context, const String &name, SetScope scope, Value target_value) { +void PhysicalSet::SetGenericVariable(ClientContext &context, idx_t setting_index, SetScope scope, Value target_value) { if (scope == SetScope::GLOBAL) { auto &config = DBConfig::GetConfig(context); - config.SetOption(name, std::move(target_value)); + config.SetOption(setting_index, std::move(target_value)); } else { auto &client_config = ClientConfig::GetConfig(context); - client_config.set_variables[name.ToStdString()] = std::move(target_value); + client_config.user_settings.SetUserSetting(setting_index, std::move(target_value)); } } @@ -26,7 +26,39 @@ void PhysicalSet::SetExtensionVariable(ClientContext &context, ExtensionOption & if (scope == SetScope::AUTOMATIC) { scope = extension_option.default_scope; } - SetGenericVariable(context, name, scope, std::move(target_value)); + auto setting_index = extension_option.setting_index.GetIndex(); + SetGenericVariable(context, setting_index, scope, std::move(target_value)); +} + +SetScope PhysicalSet::GetSettingScope(const ConfigurationOption &option, SetScope variable_scope) { + if (variable_scope == SetScope::AUTOMATIC) { + if (option.set_local) { + return SetScope::SESSION; + } + if (option.set_global) { + return SetScope::GLOBAL; + } + // generic setting + switch (option.scope) { + case SettingScopeTarget::LOCAL_ONLY: + case SettingScopeTarget::LOCAL_DEFAULT: + return SetScope::SESSION; + case SettingScopeTarget::GLOBAL_ONLY: + case SettingScopeTarget::GLOBAL_DEFAULT: + return SetScope::GLOBAL; + default: + throw InvalidInputException("Setting \"%s\" does not have a valid scope defined", option.name); + } + } + if (variable_scope == SetScope::SESSION && option.scope == SettingScopeTarget::GLOBAL_ONLY) { + throw InvalidInputException("Setting \"%s\" cannot be set as a session variable - it can only be set globally", + option.name); + } + if (variable_scope == SetScope::GLOBAL && option.scope == SettingScopeTarget::LOCAL_ONLY) { + throw InvalidInputException( + "Setting \"%s\" cannot be set as a global variable - it can only be set per session", option.name); + } + return variable_scope; } SourceResultType PhysicalSet::GetDataInternal(ExecutionContext &context, DataChunk &chunk, @@ -36,28 +68,18 @@ SourceResultType PhysicalSet::GetDataInternal(ExecutionContext &context, DataChu config.CheckLock(name); auto option = DBConfig::GetOptionByName(name); if (!option) { + ExtensionOption extension_option; // check if this is an extra extension variable - auto entry = config.extension_parameters.find(name.ToStdString()); - if (entry == config.extension_parameters.end()) { + if (!config.TryGetExtensionOption(name, extension_option)) { auto extension_name = Catalog::AutoloadExtensionByConfigName(context.client, name); - entry = config.extension_parameters.find(name.ToStdString()); - if (entry == config.extension_parameters.end()) { + if (!config.TryGetExtensionOption(name, extension_option)) { throw InvalidInputException("Extension parameter %s was not found after autoloading", name); } } - SetExtensionVariable(context.client, entry->second, name, scope, value); + SetExtensionVariable(context.client, extension_option, name, scope, value); return SourceResultType::FINISHED; } - SetScope variable_scope = scope; - if (variable_scope == SetScope::AUTOMATIC) { - if (option->set_local) { - variable_scope = SetScope::SESSION; - } else if (option->set_global) { - variable_scope = SetScope::GLOBAL; - } else { - variable_scope = option->default_scope; - } - } + SetScope variable_scope = GetSettingScope(*option, scope); Value input_val = value.CastAs(context.client, DBConfig::ParseLogicalType(option->parameter_type)); if (option->default_value) { @@ -65,7 +87,8 @@ SourceResultType PhysicalSet::GetDataInternal(ExecutionContext &context, DataChu SettingCallbackInfo info(context.client, variable_scope); option->set_callback(info, input_val); } - SetGenericVariable(context.client, option->name, variable_scope, std::move(input_val)); + auto setting_index = option->setting_idx.GetIndex(); + SetGenericVariable(context.client, setting_index, variable_scope, std::move(input_val)); return SourceResultType::FINISHED; } switch (variable_scope) { diff --git a/src/duckdb/src/execution/operator/helper/physical_streaming_limit.cpp b/src/duckdb/src/execution/operator/helper/physical_streaming_limit.cpp index 82dcdbe79..a88ed7269 100644 --- a/src/duckdb/src/execution/operator/helper/physical_streaming_limit.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_streaming_limit.cpp @@ -54,6 +54,9 @@ OperatorResultType PhysicalStreamingLimit::Execute(ExecutionContext &context, Da if (PhysicalLimit::HandleOffset(input, current_offset, offset.GetIndex(), limit.GetIndex())) { chunk.Reference(input); } + if (current_offset >= limit.GetIndex() + offset.GetIndex()) { + return chunk.size() == 0 ? OperatorResultType::FINISHED : OperatorResultType::HAVE_MORE_OUTPUT; + } return OperatorResultType::NEED_MORE_INPUT; } diff --git a/src/duckdb/src/execution/operator/helper/physical_transaction.cpp b/src/duckdb/src/execution/operator/helper/physical_transaction.cpp index 8e34f10b7..2e75990ca 100644 --- a/src/duckdb/src/execution/operator/helper/physical_transaction.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_transaction.cpp @@ -32,7 +32,7 @@ SourceResultType PhysicalTransaction::GetDataInternal(ExecutionContext &context, if (info->modifier == TransactionModifierType::TRANSACTION_READ_ONLY) { client.transaction.SetReadOnly(); } - if (DBConfig::GetSetting(context.client)) { + if (Settings::Get(context.client)) { // if immediate transaction mode is enabled then start all transactions immediately auto databases = DatabaseManager::Get(client).GetDatabases(client); for (auto &db : databases) { diff --git a/src/duckdb/src/execution/operator/join/physical_hash_join.cpp b/src/duckdb/src/execution/operator/join/physical_hash_join.cpp index 12ec306b8..e7fb060b1 100644 --- a/src/duckdb/src/execution/operator/join/physical_hash_join.cpp +++ b/src/duckdb/src/execution/operator/join/physical_hash_join.cpp @@ -707,7 +707,7 @@ class HashJoinRepartitionEvent : public BasePipelineEvent { bool JoinFilterPushdownInfo::CanUseInFilter(const ClientContext &context, optional_ptr ht, const ExpressionType &cmp) const { - auto dynamic_or_filter_threshold = DBConfig::GetSetting(context); + auto dynamic_or_filter_threshold = Settings::Get(context); return ht && ht->Count() > 1 && ht->Count() <= dynamic_or_filter_threshold && cmp == ExpressionType::COMPARE_EQUAL; } diff --git a/src/duckdb/src/execution/operator/join/physical_iejoin.cpp b/src/duckdb/src/execution/operator/join/physical_iejoin.cpp index 5d26425e3..1fab83085 100644 --- a/src/duckdb/src/execution/operator/join/physical_iejoin.cpp +++ b/src/duckdb/src/execution/operator/join/physical_iejoin.cpp @@ -1,6 +1,7 @@ #include "duckdb/execution/operator/join/physical_iejoin.hpp" #include "duckdb/common/atomic.hpp" +#include "duckdb/common/bit_utils.hpp" #include "duckdb/common/row_operations/row_operations.hpp" #include "duckdb/common/sorting/sort_key.hpp" #include "duckdb/main/client_context.hpp" @@ -327,16 +328,16 @@ class IEJoinGlobalSourceState : public GlobalSourceState { //! Stop producing tasks atomic stopped; //! The number of completed tasks for each stage - array, size_t(IEJoinSourceStage::DONE)> completed; + array, static_cast(IEJoinSourceStage::DONE)> completed; //! L1 unique_ptr l1; //! L2 unique_ptr l2; //! Li - vector li; + unsafe_vector li; //! P - vector p; + unsafe_vector p; // Join queue state idx_t l2_blocks = 0; @@ -386,8 +387,8 @@ struct IEJoinUnion { const ChunkRange &range); template - static vector ExtractColumn(SortedTable &table, idx_t col_idx) { - vector result; + static void ExtractColumn(SortedTable &table, idx_t col_idx, unsafe_vector &result) { + result.clear(); result.reserve(table.count); auto &collection = *table.sorted->payload_data; @@ -400,13 +401,9 @@ struct IEJoinUnion { while (collection.Scan(state, payload)) { const auto count = payload.size(); - const auto data_ptr = FlatVector::GetData(payload.data[0]); - for (idx_t i = 0; i < count; i++) { - result.push_back(UnsafeNumericCast(data_ptr[i])); - } + const auto data_ptr = reinterpret_cast(FlatVector::GetData(payload.data[0])); + result.insert(result.end(), data_ptr, data_ptr + count); } - - return result; } class UnionIterator { @@ -422,11 +419,27 @@ struct IEJoinUnion { index = i; } + inline idx_t GetChunkIndex() const { + idx_t chunk_idx; + idx_t tuple_idx; + state->RandomAccess(chunk_idx, tuple_idx, index); + return chunk_idx; + } + + inline void SetChunkIndex(idx_t chunk_idx) { + index = state->GetDivisor() * chunk_idx; + } + UnionIterator &operator++() { ++index; return *this; } + void Repin() { + state->SetKeepPinned(true); + state->SetPinPayload(true); + } + unique_ptr state; idx_t index = 0; const bool strict; @@ -446,7 +459,7 @@ struct IEJoinUnion { IEJoinGlobalSourceState &gsource; //! Inverted loop - idx_t JoinComplexBlocks(vector &lsel, vector &rsel); + idx_t JoinComplexBlocks(unsafe_vector &lsel, unsafe_vector &rsel); //! B vector bit_array; @@ -462,8 +475,6 @@ struct IEJoinUnion { idx_t i; idx_t n_j; idx_t j; - unique_ptr op1; - unique_ptr off1; unique_ptr op2; unique_ptr off2; int64_t lrid; @@ -548,10 +559,6 @@ idx_t IEJoinUnion::AppendKey(ExecutionContext &context, InterruptState &interrup IEJoinUnion::IEJoinUnion(IEJoinGlobalSourceState &gsource, const ChunkRange &chunks) : gsource(gsource), n(0), i(0) { auto &op = gsource.op; - auto &l1 = *gsource.l1; - const auto strict1 = IsStrictComparison(op.conditions[0].comparison); - op1 = make_uniq(l1, strict1); - off1 = make_uniq(l1, strict1); // 7. initialize bit-array B (|B| = n), and set all bits to 0 auto &l2 = *gsource.l2; @@ -620,6 +627,7 @@ bool IEJoinUnion::NextRow() { auto &li = gsource.li; auto &p = gsource.p; + auto pinned_idx = off2->GetChunkIndex(); for (; i < n; ++i) { // 12. pos ← P[i] auto pos = p[i]; @@ -631,14 +639,19 @@ bool IEJoinUnion::NextRow() { // 16. B[pos] ← 1 op2->SetIndex(i); for (; off2->GetIndex() < n_j; ++(*off2)) { + // Prevent buildup of pinned blocks + if (off2->GetChunkIndex() != pinned_idx) { + off2->Repin(); + pinned_idx = off2->GetChunkIndex(); + } if (!Compare(off2_itr[off2->GetIndex()], op2_itr[op2->GetIndex()], strict)) { break; } const auto p2 = p[off2->GetIndex()]; if (li[p2] < 0) { // Only mark rhs matches. - bit_mask.SetValid(p2); - bloom_filter.SetValid(p2 / BLOOM_CHUNK_BITS); + bit_mask.SetValidUnsafe(p2); + bloom_filter.SetValidUnsafe(p2 / BLOOM_CHUNK_BITS); } } @@ -664,44 +677,61 @@ static idx_t NextValid(const ValidityMask &bits, idx_t j, const idx_t n) { // which gives 64:1. idx_t entry_idx, idx_in_entry; bits.GetEntryIndex(j, entry_idx, idx_in_entry); - auto entry = bits.GetValidityEntry(entry_idx++); - // Trim the bits before the start position - entry &= (ValidityMask::ValidityBuffer::MAX_ENTRY << idx_in_entry); + // Copy first entry to local and trim the bits before the start position + auto first_entry = bits.GetValidityEntryUnsafe(entry_idx++); + first_entry &= (ValidityMask::ValidityBuffer::MAX_ENTRY << idx_in_entry); - // Check the non-ragged entries - for (const auto entry_count = bits.EntryCount(n); entry_idx < entry_count; ++entry_idx) { - if (entry) { - for (; idx_in_entry < bits.BITS_PER_VALUE; ++idx_in_entry, ++j) { - if (bits.RowIsValid(entry, idx_in_entry)) { - return j; - } + // If the first entry has a valid bit, we can return immediately + if (first_entry) { + return j + CountZeros::Trailing(first_entry) - idx_in_entry; + } + + // The first entry did not have a valid bit + j += ValidityMask::BITS_PER_VALUE - idx_in_entry; + + // Loop over non-ragged entries + const auto entry_count_minus_one = bits.EntryCount(n) - 1; + const auto entry_idx_before = entry_idx; + + // The compiler has a hard time optimizing this loop for some reason + // Creating a static inner loop like this improves performance by almost 2x + static constexpr idx_t NEXT_VALID_UNROLL = 8; + for (; entry_idx + NEXT_VALID_UNROLL < entry_count_minus_one; entry_idx += NEXT_VALID_UNROLL) { + for (idx_t unroll_idx = 0; unroll_idx < NEXT_VALID_UNROLL; unroll_idx++) { + const auto unroll_entry_idx = entry_idx + unroll_idx; + const auto &entry = bits.GetValidityEntryUnsafe(unroll_entry_idx); + if (entry) { + return j + (unroll_entry_idx - entry_idx_before) * ValidityMask::BITS_PER_VALUE + + CountZeros::Trailing(entry); } - } else { - j += bits.BITS_PER_VALUE - idx_in_entry; } - - entry = bits.GetValidityEntry(entry_idx); - idx_in_entry = 0; } - // Check the final entry - for (; j < n; ++idx_in_entry, ++j) { - if (bits.RowIsValid(entry, idx_in_entry)) { - return j; + for (; entry_idx < entry_count_minus_one; ++entry_idx) { + const auto &entry = bits.GetValidityEntryUnsafe(entry_idx); + if (entry) { + return j + (entry_idx - entry_idx_before) * ValidityMask::BITS_PER_VALUE + + CountZeros::Trailing(entry); } } - return j; + // Update j once after the loop so we don't have to update it in each iteration + j += (entry_idx - entry_idx_before) * ValidityMask::BITS_PER_VALUE; + + // Check the final entry + return j >= n ? n : j + CountZeros::Trailing(bits.GetValidityEntryUnsafe(entry_idx)); } -idx_t IEJoinUnion::JoinComplexBlocks(vector &lsel, vector &rsel) { - auto &li = gsource.li; +idx_t IEJoinUnion::JoinComplexBlocks(unsafe_vector &lsel, unsafe_vector &rsel) { + const auto &li = gsource.li; + + // Release pinned blocks + op2->Repin(); + off2->Repin(); // 8. initialize join result as an empty list for tuple pairs idx_t result_count = 0; - lsel.resize(0); - rsel.resize(0); // 11. for(i←1 to n) do while (i < n) { @@ -731,8 +761,8 @@ idx_t IEJoinUnion::JoinComplexBlocks(vector &lsel, vector &rsel) { D_ASSERT(lrid > 0 && rrid < 0); // 15. add tuples w.r.t. (L1[j], L1[i]) to join result - lsel.emplace_back(idx_t(+lrid - 1)); - rsel.emplace_back(idx_t(-rrid - 1)); + lsel[result_count] = static_cast(+lrid - 1); + rsel[result_count] = static_cast(-rrid - 1); ++result_count; if (result_count == STANDARD_VECTOR_SIZE) { // out of space! @@ -841,7 +871,7 @@ void IEJoinGlobalSourceState::ExecuteLiTask(ClientContext &client) { // We don't actually need the L1 column, just its sort key, which is in the sort blocks l1->GetSortedRun(client); - li = IEJoinUnion::ExtractColumn(*l1, 1); + IEJoinUnion::ExtractColumn(*l1, 1, li); } void IEJoinGlobalSourceState::ExecutePermutationTask(ClientContext &client) { @@ -849,7 +879,7 @@ void IEJoinGlobalSourceState::ExecutePermutationTask(ClientContext &client) { l2->GetSortedRun(client); // 6. compute the permutation array P of L2 w.r.t. L1 - p = IEJoinUnion::ExtractColumn(*l2, 0); + IEJoinUnion::ExtractColumn(*l2, 0, p); } class IEJoinLocalSourceState : public LocalSourceState { @@ -957,7 +987,7 @@ class IEJoinLocalSourceState : public LocalSourceState { idx_t left_block_index; unique_ptr left_iterator; TupleDataChunkState left_chunk_state; - vector lsel; + unsafe_vector lsel; DataChunk lpayload; unique_ptr left_scan_state; @@ -965,7 +995,7 @@ class IEJoinLocalSourceState : public LocalSourceState { idx_t right_block_index; unique_ptr right_iterator; TupleDataChunkState right_chunk_state; - vector rsel; + unsafe_vector rsel; DataChunk rpayload; unique_ptr right_scan_state; @@ -981,7 +1011,7 @@ class IEJoinLocalSourceState : public LocalSourceState { DataChunk unprojected; // Outer joins - vector outer_sel; + unsafe_vector outer_sel; idx_t outer_idx; idx_t outer_count; bool *left_matches; diff --git a/src/duckdb/src/execution/operator/join/physical_piecewise_merge_join.cpp b/src/duckdb/src/execution/operator/join/physical_piecewise_merge_join.cpp index 30cd49558..18ae8f747 100644 --- a/src/duckdb/src/execution/operator/join/physical_piecewise_merge_join.cpp +++ b/src/duckdb/src/execution/operator/join/physical_piecewise_merge_join.cpp @@ -453,7 +453,7 @@ struct ChunkMergeInfo { //! The left chunk offsets that match SelectionVector lhs; //! The right table offsets that match - vector rhs; + unsafe_vector rhs; ChunkMergeInfo(ExternalBlockIteratorState &state, idx_t block_idx, idx_t &entry_idx, idx_t not_null) : state(state), block_idx(block_idx), not_null(not_null), entry_idx(entry_idx), lhs(STANDARD_VECTOR_SIZE) { diff --git a/src/duckdb/src/execution/operator/join/physical_range_join.cpp b/src/duckdb/src/execution/operator/join/physical_range_join.cpp index 7b324c3d9..95f68f90a 100644 --- a/src/duckdb/src/execution/operator/join/physical_range_join.cpp +++ b/src/duckdb/src/execution/operator/join/physical_range_join.cpp @@ -155,6 +155,7 @@ class RangeJoinMaterializeTask : public ExecutorTask { if (!table.sorted) { table.MaterializeEmpty(execution.client); } + table.global_source.reset(); } event->FinishTask(); @@ -221,6 +222,7 @@ void PhysicalRangeJoin::GlobalSortedTable::GetSortedRun(ClientContext &client) { if (!sorted) { MaterializeEmpty(client); } + global_source.reset(); } void PhysicalRangeJoin::GlobalSortedTable::Materialize(ExecutionContext &context, InterruptState &interrupt) { @@ -403,7 +405,7 @@ template static void TemplatedSliceSortedPayload(DataChunk &chunk, const SortedRun &sorted_run, ExternalBlockIteratorState &state, Vector &sort_key_pointers, SortedRunScanState &scan_state, const idx_t chunk_idx, - const vector &result) { + const unsafe_vector &result) { using SORT_KEY = SortKey; using BLOCK_ITERATOR = block_iterator_t; BLOCK_ITERATOR itr(state, chunk_idx, 0); @@ -421,7 +423,7 @@ static void TemplatedSliceSortedPayload(DataChunk &chunk, const SortedRun &sorte void PhysicalRangeJoin::SliceSortedPayload(DataChunk &chunk, GlobalSortedTable &table, ExternalBlockIteratorState &state, TupleDataChunkState &chunk_state, - const idx_t chunk_idx, const vector &result, + const idx_t chunk_idx, const unsafe_vector &result, SortedRunScanState &scan_state) { auto &sorted = *table.sorted; auto &sort_keys = chunk_state.row_locations; diff --git a/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp b/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp index 72b1b7d13..53b719eb1 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp @@ -106,9 +106,9 @@ class CollectionMerger { data_table.ResetOptimisticCollection(context, collection_indexes[i]); } result_collection.FinalizeAppend(TransactionData(0, 0), append_state); - writer.WriteLastRowGroup(optimistic_collection); + writer.WriteUnflushedRowGroups(optimistic_collection); } else if (batch_type == RowGroupBatchType::NOT_FLUSHED) { - writer.WriteLastRowGroup(optimistic_collection); + writer.WriteUnflushedRowGroups(optimistic_collection); } collection_indexes.clear(); @@ -380,7 +380,7 @@ void BatchInsertGlobalState::AddCollection(ClientContext &context, const idx_t b auto new_count = collection.GetTotalRows(); auto batch_type = new_count < row_group_size ? RowGroupBatchType::NOT_FLUSHED : RowGroupBatchType::FLUSHED; if (batch_type == RowGroupBatchType::FLUSHED && writer) { - writer->WriteLastRowGroup(optimistic_collection); + writer->WriteUnflushedRowGroups(optimistic_collection); } lock_guard l(lock); insert_count += new_count; @@ -672,10 +672,9 @@ SinkFinalizeType PhysicalBatchInsert::Finalize(Pipeline &pipeline, Event &event, memory_manager.ReduceUnflushedMemory(entry.unflushed_memory); auto &optimistic_collection = data_table.GetOptimisticCollection(context, entry.collection_index); auto &collection = *optimistic_collection.collection; - collection.Scan(transaction, [&](DataChunk &insert_chunk) { + for (auto &insert_chunk : collection.Chunks(transaction)) { data_table.LocalAppend(append_state, context, insert_chunk, false); - return true; - }); + } data_table.ResetOptimisticCollection(context, entry.collection_index); } diff --git a/src/duckdb/src/execution/operator/persistent/physical_copy_database.cpp b/src/duckdb/src/execution/operator/persistent/physical_copy_database.cpp index f0c5952f3..791e1ddbe 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_copy_database.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_copy_database.cpp @@ -79,7 +79,7 @@ SourceResultType PhysicalCopyDatabase::GetDataInternal(ExecutionContext &context IndexStorageInfo storage_info(create_index_info.index_name); storage_info.options.emplace("v1_0_0_storage", false); - auto unbound_index = make_uniq(create_index_info.Copy(), storage_info, + auto unbound_index = make_uniq(create_index_info.Copy(), std::move(storage_info), data_table.GetTableIOManager(), catalog.GetAttached()); data_table.AddIndex(std::move(unbound_index)); diff --git a/src/duckdb/src/execution/operator/persistent/physical_copy_to_file.cpp b/src/duckdb/src/execution/operator/persistent/physical_copy_to_file.cpp index a96ea4d6d..35881a5ac 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_copy_to_file.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_copy_to_file.cpp @@ -51,7 +51,7 @@ class CopyToFunctionGlobalState : public GlobalSinkState { explicit CopyToFunctionGlobalState(ClientContext &context_p) : context(context_p), finalized(false), initialized(false), rows_copied(0), last_file_offset(0), file_write_lock_if_rotating(make_uniq()) { - max_open_files = DBConfig::GetSetting(context); + max_open_files = Settings::Get(context); } ~CopyToFunctionGlobalState() override; @@ -120,7 +120,11 @@ class CopyToFunctionGlobalState : public GlobalSinkState { string p_dir; p_dir += HivePartitioning::Escape(partition_col_name); p_dir += "="; - p_dir += HivePartitioning::Escape(partition_value.ToString()); + if (partition_value.IsNull()) { + p_dir += "__HIVE_DEFAULT_PARTITION__"; + } else { + p_dir += HivePartitioning::Escape(partition_value.ToString()); + } path = fs.JoinPath(path, p_dir); CreateDir(path, fs); } @@ -260,7 +264,12 @@ CopyToFunctionGlobalState::~CopyToFunctionGlobalState() { // If we reach here, the query failed before Finalize was called auto &fs = FileSystem::GetFileSystem(context); for (auto &file : created_files) { - fs.TryRemoveFile(file); + try { + fs.TryRemoveFile(file); + } catch (...) { + // TryRemoveFile migth fail for a varieaty of reasons, but we can't really propagate error codes here, so + // best effort cleanup + } } } @@ -275,7 +284,7 @@ class CopyToFunctionLocalState : public LocalSinkState { public: explicit CopyToFunctionLocalState(ClientContext &context, unique_ptr local_state) : local_state(std::move(local_state)) { - partitioned_write_flush_threshold = DBConfig::GetSetting(context); + partitioned_write_flush_threshold = Settings::Get(context); } unique_ptr global_state; unique_ptr local_state; @@ -410,11 +419,6 @@ void CheckDirectory(FileSystem &fs, const string &file_path, CopyOverwriteMode o // with overwrite or ignore we fully ignore the presence of any files instead of erasing them return; } - if (fs.IsRemoteFile(file_path) && overwrite_mode == CopyOverwriteMode::COPY_OVERWRITE) { - // we can only remove files for local file systems currently - // as remote file systems (e.g. S3) do not support RemoveFile - throw NotImplementedException("OVERWRITE is not supported for remote file systems"); - } vector file_list; vector directory_list; directory_list.push_back(file_path); @@ -684,23 +688,25 @@ unique_ptr PhysicalCopyToFile::GetGlobalSourceState(ClientCon return make_uniq(); } -void PhysicalCopyToFile::ReturnStatistics(DataChunk &chunk, idx_t row_idx, CopyToFileInfo &info) { - auto &file_stats = *info.file_stats; +namespace { - // filename VARCHAR - chunk.SetValue(0, row_idx, info.file_path); - // count BIGINT - chunk.SetValue(1, row_idx, Value::UBIGINT(file_stats.row_count)); - // file size bytes BIGINT - chunk.SetValue(2, row_idx, Value::UBIGINT(file_stats.file_size_bytes)); - // footer size bytes BIGINT - chunk.SetValue(3, row_idx, file_stats.footer_size_bytes); - // column statistics map(varchar, map(varchar, varchar)) +struct ColumnStatsMapData { + vector keys; + vector values; +}; + +} // namespace + +static ColumnStatsMapData +CreateColumnStatistics(const case_insensitive_map_t> &column_statistics) { + ColumnStatsMapData result; + + //! Use a map to make sure the result has a consistent ordering map stats; - for (auto &entry : file_stats.column_statistics) { + for (auto &entry : column_statistics) { map per_column_stats; for (auto &stats_entry : entry.second) { - per_column_stats.insert(make_pair(stats_entry.first, stats_entry.second)); + per_column_stats.emplace(stats_entry.first, stats_entry.second); } vector stats_keys; vector stats_values; @@ -710,16 +716,32 @@ void PhysicalCopyToFile::ReturnStatistics(DataChunk &chunk, idx_t row_idx, CopyT } auto map_value = Value::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR, std::move(stats_keys), std::move(stats_values)); - stats.insert(make_pair(entry.first, std::move(map_value))); + stats.emplace(entry.first, std::move(map_value)); } - vector keys; - vector values; for (auto &entry : stats) { - keys.emplace_back(entry.first); - values.emplace_back(std::move(entry.second)); + result.keys.emplace_back(entry.first); + result.values.emplace_back(std::move(entry.second)); } + return result; +} + +void PhysicalCopyToFile::ReturnStatistics(DataChunk &chunk, idx_t row_idx, CopyToFileInfo &info) { + auto &file_stats = *info.file_stats; + + // filename VARCHAR + chunk.SetValue(0, row_idx, info.file_path); + // count BIGINT + chunk.SetValue(1, row_idx, Value::UBIGINT(file_stats.row_count)); + // file size bytes BIGINT + chunk.SetValue(2, row_idx, Value::UBIGINT(file_stats.file_size_bytes)); + // footer size bytes BIGINT + chunk.SetValue(3, row_idx, file_stats.footer_size_bytes); + // column statistics map(varchar, map(varchar, varchar)) + auto column_stats = CreateColumnStatistics(file_stats.column_statistics); auto map_val_type = LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR); - chunk.SetValue(4, row_idx, Value::MAP(LogicalType::VARCHAR, map_val_type, std::move(keys), std::move(values))); + chunk.SetValue( + 4, row_idx, + Value::MAP(LogicalType::VARCHAR, map_val_type, std::move(column_stats.keys), std::move(column_stats.values))); // partition_keys map(varchar, varchar) chunk.SetValue(5, row_idx, info.partition_keys); diff --git a/src/duckdb/src/execution/operator/persistent/physical_delete.cpp b/src/duckdb/src/execution/operator/persistent/physical_delete.cpp index eaef83502..4603e6147 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_delete.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_delete.cpp @@ -89,14 +89,13 @@ SinkResultType PhysicalDelete::Sink(ExecutionContext &context, DataChunk &chunk, auto &local_storage = LocalStorage::Get(context.client, table.db); auto storage = local_storage.GetStorage(table); unordered_set indexed_column_id_set; - storage->delete_indexes.Scan([&](Index &index) { + for (auto &index : storage->delete_indexes.Indexes()) { if (!index.IsBound() || !index.IsUnique()) { - return false; + continue; } auto &set = index.GetColumnIdSet(); indexed_column_id_set.insert(set.begin(), set.end()); - return false; - }); + } for (auto &col : indexed_column_id_set) { column_ids.emplace_back(col); } @@ -134,17 +133,16 @@ SinkResultType PhysicalDelete::Sink(ExecutionContext &context, DataChunk &chunk, auto &local_storage = LocalStorage::Get(context.client, table.db); auto storage = local_storage.GetStorage(table); IndexAppendInfo index_append_info(IndexAppendMode::IGNORE_DUPLICATES, nullptr); - storage->delete_indexes.Scan([&](Index &index) { + for (auto &index : storage->delete_indexes.Indexes()) { if (!index.IsBound() || !index.IsUnique()) { - return false; + continue; } auto &bound_index = index.Cast(); auto error = bound_index.Append(l_state.delete_chunk, row_ids, index_append_info); if (error.HasError()) { throw InternalException("failed to update delete ART in physical delete: ", error.Message()); } - return false; - }); + } } auto deleted_count = table.Delete(*l_state.delete_state, context.client, row_ids, chunk.size()); diff --git a/src/duckdb/src/execution/operator/persistent/physical_insert.cpp b/src/duckdb/src/execution/operator/persistent/physical_insert.cpp index b0b644ca6..3f11e3955 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_insert.cpp @@ -532,28 +532,26 @@ idx_t PhysicalInsert::OnConflictHandling(TableCatalogEntry &table, ExecutionCont if (conflict_info.column_ids.empty()) { auto &global_indexes = data_table.GetDataTableInfo()->GetIndexes(); // We care about every index that applies to the table if no ON CONFLICT (...) target is given - global_indexes.Scan([&](Index &index) { + for (auto &index : global_indexes.Indexes()) { if (!index.IsUnique()) { - return false; + continue; } D_ASSERT(index.IsBound()); if (conflict_info.ConflictTargetMatches(index)) { matching_indexes.insert(index); } - return false; - }); + } auto &local_indexes = local_storage.GetIndexes(context.client, data_table); - local_indexes.Scan([&](Index &index) { + for (auto &index : local_indexes.Indexes()) { if (!index.IsUnique()) { - return false; + continue; } D_ASSERT(index.IsBound()); if (conflict_info.ConflictTargetMatches(index)) { auto &bound_index = index.Cast(); matching_indexes.insert(bound_index); } - return false; - }); + } } auto inner_conflicts = CheckDistinctness(insert_chunk, conflict_info, matching_indexes); @@ -703,14 +701,13 @@ SinkCombineResultType PhysicalInsert::Combine(ExecutionContext &context, Operato LocalAppendState append_state; storage.InitializeLocalAppend(append_state, table, context.client, bound_constraints); auto &transaction = DuckTransaction::Get(context.client, table.catalog); - collection.Scan(transaction, [&](DataChunk &insert_chunk) { + for (auto &insert_chunk : collection.Chunks(transaction)) { storage.LocalAppend(append_state, context.client, insert_chunk, false); - return true; - }); + } storage.FinalizeLocalAppend(append_state); } else { // we have written rows to disk optimistically - merge directly into the transaction-local storage - lstate.optimistic_writer->WriteLastRowGroup(optimistic_collection); + lstate.optimistic_writer->WriteUnflushedRowGroups(optimistic_collection); lstate.optimistic_writer->FinalFlush(); gstate.table.GetStorage().LocalMerge(context.client, optimistic_collection); auto &optimistic_writer = gstate.table.GetStorage().GetOptimisticWriter(context.client); diff --git a/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp b/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp index c38036e1b..5ac221ec0 100644 --- a/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp +++ b/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp @@ -30,8 +30,7 @@ PhysicalTableScan::PhysicalTableScan(PhysicalPlan &physical_plan, vector(context); + physical_table_scan_execution_strategy = Settings::Get(context); if (op.dynamic_filters && op.dynamic_filters->HasFilters()) { table_filters = op.dynamic_filters->GetFinalTableFilters(op, op.table_filters.get()); @@ -285,10 +284,26 @@ void AddProjectionNames(const ColumnIndex &index, const string &name, const Logi result += name; return; } - auto &child_types = StructType::GetChildTypes(type); - for (auto &child_index : index.GetChildIndexes()) { - auto &ele = child_types[child_index.GetPrimaryIndex()]; - AddProjectionNames(child_index, name + "." + ele.first, ele.second, result); + + if (type.id() == LogicalTypeId::STRUCT) { + auto &child_types = StructType::GetChildTypes(type); + for (auto &child_index : index.GetChildIndexes()) { + if (child_index.HasPrimaryIndex()) { + auto &ele = child_types[child_index.GetPrimaryIndex()]; + AddProjectionNames(child_index, name + "." + ele.first, ele.second, result); + } else { + auto field_type = child_index.HasType() ? child_index.GetType() : LogicalType::VARIANT(); + AddProjectionNames(child_index, name + "." + child_index.GetFieldName(), field_type, result); + } + } + } else if (type.id() == LogicalTypeId::VARIANT) { + for (auto &child_index : index.GetChildIndexes()) { + D_ASSERT(!child_index.HasPrimaryIndex()); + auto field_type = child_index.HasType() ? child_index.GetType() : LogicalType::VARIANT(); + AddProjectionNames(child_index, name + "." + child_index.GetFieldName(), field_type, result); + } + } else { + throw InternalException("Unexpected type (%s) in AddProjectionNames", type.ToString()); } } diff --git a/src/duckdb/src/execution/operator/schema/physical_attach.cpp b/src/duckdb/src/execution/operator/schema/physical_attach.cpp index 9ec3c152d..638591741 100644 --- a/src/duckdb/src/execution/operator/schema/physical_attach.cpp +++ b/src/duckdb/src/execution/operator/schema/physical_attach.cpp @@ -33,33 +33,6 @@ SourceResultType PhysicalAttach::GetDataInternal(ExecutionContext &context, Data // check ATTACH IF NOT EXISTS auto &db_manager = DatabaseManager::Get(context.client); - if (info->on_conflict == OnCreateConflict::IGNORE_ON_CONFLICT || - info->on_conflict == OnCreateConflict::REPLACE_ON_CONFLICT) { - // constant-time lookup in the catalog for the db name - auto existing_db = db_manager.GetDatabase(name); - if (existing_db) { - if ((existing_db->IsReadOnly() && options.access_mode == AccessMode::READ_WRITE) || - (!existing_db->IsReadOnly() && options.access_mode == AccessMode::READ_ONLY)) { - auto existing_mode = existing_db->IsReadOnly() ? AccessMode::READ_ONLY : AccessMode::READ_WRITE; - auto existing_mode_str = EnumUtil::ToString(existing_mode); - auto attached_mode = EnumUtil::ToString(options.access_mode); - throw BinderException("Database \"%s\" is already attached in %s mode, cannot re-attach in %s mode", - name, existing_mode_str, attached_mode); - } - if (!options.default_table.name.empty()) { - existing_db->GetCatalog().SetDefaultTable(options.default_table.schema, options.default_table.name); - } - if (info->on_conflict == OnCreateConflict::REPLACE_ON_CONFLICT) { - // allow custom catalogs to override this behavior - if (!existing_db->GetCatalog().HasConflictingAttachOptions(path, options)) { - return SourceResultType::FINISHED; - } - } else { - return SourceResultType::FINISHED; - } - } - } - db_manager.AttachDatabase(context.client, *info, options); return SourceResultType::FINISHED; } diff --git a/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp b/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp deleted file mode 100644 index c638f45b8..000000000 --- a/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#include "duckdb/execution/operator/schema/physical_create_art_index.hpp" - -#include "duckdb/catalog/catalog_entry/duck_index_entry.hpp" -#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" -#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" -#include "duckdb/execution/index/art/art_key.hpp" -#include "duckdb/execution/index/bound_index.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/main/database_manager.hpp" -#include "duckdb/storage/storage_manager.hpp" -#include "duckdb/storage/table/append_state.hpp" -#include "duckdb/common/exception/transaction_exception.hpp" -#include "duckdb/execution/index/art/art_operator.hpp" - -namespace duckdb { - -PhysicalCreateARTIndex::PhysicalCreateARTIndex(PhysicalPlan &physical_plan, LogicalOperator &op, - TableCatalogEntry &table_p, const vector &column_ids, - unique_ptr info, - vector> unbound_expressions, - idx_t estimated_cardinality, const bool sorted, - unique_ptr alter_table_info) - : PhysicalOperator(physical_plan, PhysicalOperatorType::CREATE_INDEX, op.types, estimated_cardinality), - table(table_p.Cast()), info(std::move(info)), unbound_expressions(std::move(unbound_expressions)), - sorted(sorted), alter_table_info(std::move(alter_table_info)) { - // Convert the logical column ids to physical column ids. - for (auto &column_id : column_ids) { - storage_ids.push_back(table.GetColumns().LogicalToPhysical(LogicalIndex(column_id)).index); - } -} - -//===--------------------------------------------------------------------===// -// Sink -//===--------------------------------------------------------------------===// - -class CreateARTIndexGlobalSinkState : public GlobalSinkState { -public: - //! We merge the local indexes into one global index. - unique_ptr global_index; -}; - -class CreateARTIndexLocalSinkState : public LocalSinkState { -public: - explicit CreateARTIndexLocalSinkState(ClientContext &context) : arena_allocator(Allocator::Get(context)) {}; - - unique_ptr local_index; - ArenaAllocator arena_allocator; - - DataChunk key_chunk; - unsafe_vector keys; - vector key_column_ids; - - DataChunk row_id_chunk; - unsafe_vector row_ids; -}; - -unique_ptr PhysicalCreateARTIndex::GetGlobalSinkState(ClientContext &context) const { - // Create the global sink state. - auto state = make_uniq(); - - // Create the global index. - auto &storage = table.GetStorage(); - state->global_index = make_uniq(info->index_name, info->constraint_type, storage_ids, - TableIOManager::Get(storage), unbound_expressions, storage.db); - return (std::move(state)); -} - -unique_ptr PhysicalCreateARTIndex::GetLocalSinkState(ExecutionContext &context) const { - // Create the local sink state and add the local index. - auto state = make_uniq(context.client); - auto &storage = table.GetStorage(); - state->local_index = make_uniq(info->index_name, info->constraint_type, storage_ids, - TableIOManager::Get(storage), unbound_expressions, storage.db); - - // Initialize the local sink state. - state->keys.resize(STANDARD_VECTOR_SIZE); - state->row_ids.resize(STANDARD_VECTOR_SIZE); - state->key_chunk.Initialize(Allocator::Get(context.client), state->local_index->logical_types); - state->row_id_chunk.Initialize(Allocator::Get(context.client), vector {LogicalType::ROW_TYPE}); - for (idx_t i = 0; i < state->key_chunk.ColumnCount(); i++) { - state->key_column_ids.push_back(i); - } - return std::move(state); -} - -SinkResultType PhysicalCreateARTIndex::SinkUnsorted(OperatorSinkInput &input) const { - auto &l_state = input.local_state.Cast(); - auto row_count = l_state.key_chunk.size(); - auto &art = l_state.local_index->Cast(); - - // Insert each key and its corresponding row ID. - for (idx_t i = 0; i < row_count; i++) { - auto status = art.tree.GetGateStatus(); - auto conflict_type = - ARTOperator::Insert(l_state.arena_allocator, art, art.tree, l_state.keys[i], 0, l_state.row_ids[i], status, - DeleteIndexInfo(), IndexAppendMode::DEFAULT); - D_ASSERT(conflict_type != ARTConflictType::TRANSACTION); - if (conflict_type == ARTConflictType::CONSTRAINT) { - throw ConstraintException("Data contains duplicates on indexed column(s)"); - } - } - - return SinkResultType::NEED_MORE_INPUT; -} - -SinkResultType PhysicalCreateARTIndex::SinkSorted(OperatorSinkInput &input) const { - auto &l_state = input.local_state.Cast(); - auto &storage = table.GetStorage(); - auto &l_index = l_state.local_index; - - // Construct an ART for this chunk. - auto art = make_uniq(info->index_name, l_index->GetConstraintType(), l_index->GetColumnIds(), - l_index->table_io_manager, l_index->unbound_expressions, storage.db, - l_index->Cast().allocators); - if (art->Build(l_state.keys, l_state.row_ids, l_state.key_chunk.size()) != ARTConflictType::NO_CONFLICT) { - throw ConstraintException("Data contains duplicates on indexed column(s)"); - } - - // Merge the ART into the local ART. - if (!l_index->MergeIndexes(*art)) { - throw ConstraintException("Data contains duplicates on indexed column(s)"); - } - - return SinkResultType::NEED_MORE_INPUT; -} - -SinkResultType PhysicalCreateARTIndex::Sink(ExecutionContext &context, DataChunk &chunk, - OperatorSinkInput &input) const { - D_ASSERT(chunk.ColumnCount() >= 2); - auto &l_state = input.local_state.Cast(); - l_state.arena_allocator.Reset(); - l_state.key_chunk.ReferenceColumns(chunk, l_state.key_column_ids); - - // Check for NULLs, if we are creating a PRIMARY KEY. - // FIXME: Later, we want to ensure that we skip the NULL check for any non-PK alter. - if (alter_table_info) { - auto row_count = l_state.key_chunk.size(); - for (idx_t i = 0; i < l_state.key_chunk.ColumnCount(); i++) { - if (VectorOperations::HasNull(l_state.key_chunk.data[i], row_count)) { - throw ConstraintException("NOT NULL constraint failed: %s", info->index_name); - } - } - } - - l_state.local_index->Cast().GenerateKeyVectors( - l_state.arena_allocator, l_state.key_chunk, chunk.data[chunk.ColumnCount() - 1], l_state.keys, l_state.row_ids); - - if (sorted) { - return SinkSorted(input); - } - return SinkUnsorted(input); -} - -SinkCombineResultType PhysicalCreateARTIndex::Combine(ExecutionContext &context, - OperatorSinkCombineInput &input) const { - auto &g_state = input.global_state.Cast(); - - // Merge the local index into the global index. - auto &l_state = input.local_state.Cast(); - if (!g_state.global_index->MergeIndexes(*l_state.local_index)) { - throw ConstraintException("Data contains duplicates on indexed column(s)"); - } - - return SinkCombineResultType::FINISHED; -} - -SinkFinalizeType PhysicalCreateARTIndex::Finalize(Pipeline &pipeline, Event &event, ClientContext &context, - OperatorSinkFinalizeInput &input) const { - auto &state = input.global_state.Cast(); - - // Vacuum excess memory and verify. - state.global_index->Vacuum(); - state.global_index->Verify(); - state.global_index->VerifyAllocations(); - - auto &storage = table.GetStorage(); - if (!storage.IsMainTable()) { - throw TransactionException( - "Transaction conflict: cannot add an index to a table that has been altered or dropped"); - } - - auto &schema = table.schema; - info->column_ids = storage_ids; - - if (!alter_table_info) { - // Ensure that the index does not yet exist in the catalog. - auto entry = schema.GetEntry(schema.GetCatalogTransaction(context), CatalogType::INDEX_ENTRY, info->index_name); - if (entry) { - if (info->on_conflict != OnCreateConflict::IGNORE_ON_CONFLICT) { - throw CatalogException("Index with name \"%s\" already exists!", info->index_name); - } - // IF NOT EXISTS on existing index. We are done. - return SinkFinalizeType::READY; - } - - auto index_entry = schema.CreateIndex(schema.GetCatalogTransaction(context), *info, table).get(); - D_ASSERT(index_entry); - auto &index = index_entry->Cast(); - index.initial_index_size = state.global_index->GetInMemorySize(); - - } else { - // Ensure that there are no other indexes with that name on this table. - auto &indexes = storage.GetDataTableInfo()->GetIndexes(); - indexes.Scan([&](Index &index) { - if (index.GetIndexName() == info->index_name) { - throw CatalogException("an index with that name already exists for this table: %s", info->index_name); - } - return false; - }); - - auto &catalog = Catalog::GetCatalog(context, info->catalog); - catalog.Alter(context, *alter_table_info); - } - - // Add the index to the storage. - storage.AddIndex(std::move(state.global_index)); - return SinkFinalizeType::READY; -} - -//===--------------------------------------------------------------------===// -// Source -//===--------------------------------------------------------------------===// - -SourceResultType PhysicalCreateARTIndex::GetDataInternal(ExecutionContext &context, DataChunk &chunk, - OperatorSourceInput &input) const { - return SourceResultType::FINISHED; -} - -} // namespace duckdb diff --git a/src/duckdb/src/execution/operator/schema/physical_create_index.cpp b/src/duckdb/src/execution/operator/schema/physical_create_index.cpp index 102d9b8b8..83f4dd839 100644 --- a/src/duckdb/src/execution/operator/schema/physical_create_index.cpp +++ b/src/duckdb/src/execution/operator/schema/physical_create_index.cpp @@ -160,12 +160,11 @@ SinkFinalizeType PhysicalCreateIndex::Finalize(Pipeline &pipeline, Event &event, } else { // Ensure that there are no other indexes with that name on this table. auto &indexes = storage.GetDataTableInfo()->GetIndexes(); - indexes.Scan([&](Index &index) { + for (auto &index : indexes.Indexes()) { if (index.GetIndexName() == info->index_name) { throw CatalogException("an index with that name already exists for this table: %s", info->index_name); } - return false; - }); + } auto &catalog = Catalog::GetCatalog(context, info->catalog); catalog.Alter(context, *alter_table_info); diff --git a/src/duckdb/src/execution/operator/set/physical_recursive_cte.cpp b/src/duckdb/src/execution/operator/set/physical_recursive_cte.cpp index 1fd840709..417ae6d6d 100644 --- a/src/duckdb/src/execution/operator/set/physical_recursive_cte.cpp +++ b/src/duckdb/src/execution/operator/set/physical_recursive_cte.cpp @@ -176,6 +176,20 @@ SourceResultType PhysicalRecursiveCTE::GetDataInternal(ExecutionContext &context // Append the result to the recurring table. recurring_table->Append(result); } + } else if (ref_recurring && gstate.intermediate_table.Count() != 0) { + // we need to populate the recurring table from the intermediate table + // careful: we can not just use Combine here, because this destroys the intermediate table + // instead we need to scan and append to create a copy + // Note: as we are in the "normal" recursion case here, not the USING KEY case, + // we can just scan the intermediate table directly, instead of going through the HT + ColumnDataScanState scan_state; + gstate.intermediate_table.InitializeScan(scan_state); + DataChunk result; + result.Initialize(Allocator::DefaultAllocator(), chunk.GetTypes()); + + while (gstate.intermediate_table.Scan(scan_state, result)) { + recurring_table->Append(result); + } } working_table->Reset(); diff --git a/src/duckdb/src/execution/operator/set/physical_union.cpp b/src/duckdb/src/execution/operator/set/physical_union.cpp index e43117c92..dc1b57484 100644 --- a/src/duckdb/src/execution/operator/set/physical_union.cpp +++ b/src/duckdb/src/execution/operator/set/physical_union.cpp @@ -87,6 +87,8 @@ void PhysicalUnion::BuildPipelines(Pipeline ¤t, MetaPipeline &meta_pipelin last_child_ptr = meta_pipeline.GetLastChild(); } } + // Assign proper batch index to the union pipeline + meta_pipeline.AssignNextBatchIndex(union_pipeline); // build the union pipeline children[i].get().BuildPipelines(union_pipeline, meta_pipeline); @@ -94,9 +96,6 @@ void PhysicalUnion::BuildPipelines(Pipeline ¤t, MetaPipeline &meta_pipelin // the pointer was set, set up the dependencies meta_pipeline.AddRecursiveDependencies(dependencies, *last_child_ptr); } - // Assign proper batch index to the union pipeline - // This needs to happen after the pipelines have been built because unions can be nested - meta_pipeline.AssignNextBatchIndex(union_pipeline); } } diff --git a/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp b/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp index 8bd9837bd..647ffad19 100644 --- a/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp @@ -217,7 +217,7 @@ static bool CanUsePerfectHashAggregate(ClientContext &context, LogicalAggregate bits_per_group.push_back(required_bits); perfect_hash_bits += required_bits; // check if we have exceeded the bits for the hash - if (perfect_hash_bits > DBConfig::GetSetting(context)) { + if (perfect_hash_bits > Settings::Get(context)) { // too many bits for perfect hash return false; } diff --git a/src/duckdb/src/execution/physical_plan/plan_asof_join.cpp b/src/duckdb/src/execution/physical_plan/plan_asof_join.cpp index 3d84506fa..fba7600f2 100644 --- a/src/duckdb/src/execution/physical_plan/plan_asof_join.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_asof_join.cpp @@ -9,7 +9,7 @@ #include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/function/function_binder.hpp" -#include "duckdb/main/client_context.hpp" +#include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/expression/bound_window_expression.hpp" @@ -292,9 +292,9 @@ PhysicalOperator &PhysicalPlanGenerator::PlanAsOfJoin(LogicalComparisonJoin &op) // If there is a non-comparison predicate, we have to use NLJ. const bool has_predicate = op.predicate.get(); - const bool force_asof_join = DBConfig::GetSetting(context); + const bool force_asof_join = Settings::Get(context); if (!force_asof_join || has_predicate) { - const idx_t asof_join_threshold = DBConfig::GetSetting(context); + const idx_t asof_join_threshold = Settings::Get(context); if (has_predicate || (op.children[0]->has_estimated_cardinality && lhs_cardinality < asof_join_threshold)) { auto result = PlanAsOfLoopJoin(op, left, right); if (result) { diff --git a/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp b/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp index aeb77a800..8e8c19ed9 100644 --- a/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp @@ -51,7 +51,7 @@ PhysicalOperator &PhysicalPlanGenerator::PlanComparisonJoin(LogicalComparisonJoi break; } // TODO: Extend PWMJ to handle all comparisons and projection maps - bool prefer_range_joins = DBConfig::GetSetting(context); + bool prefer_range_joins = Settings::Get(context); prefer_range_joins = prefer_range_joins && can_iejoin; if (has_equality && !prefer_range_joins) { // Equality join with small number of keys : possible perfect join optimization @@ -63,7 +63,7 @@ PhysicalOperator &PhysicalPlanGenerator::PlanComparisonJoin(LogicalComparisonJoi } D_ASSERT(op.left_projection_map.empty()); - idx_t nested_loop_join_threshold = DBConfig::GetSetting(context); + idx_t nested_loop_join_threshold = Settings::Get(context); if (left.estimated_cardinality < nested_loop_join_threshold || right.estimated_cardinality < nested_loop_join_threshold) { can_iejoin = false; @@ -71,7 +71,7 @@ PhysicalOperator &PhysicalPlanGenerator::PlanComparisonJoin(LogicalComparisonJoi } if (can_merge && can_iejoin) { - idx_t merge_join_threshold = DBConfig::GetSetting(context); + idx_t merge_join_threshold = Settings::Get(context); if (left.estimated_cardinality < merge_join_threshold || right.estimated_cardinality < merge_join_threshold) { can_iejoin = false; } diff --git a/src/duckdb/src/execution/physical_plan/plan_explain.cpp b/src/duckdb/src/execution/physical_plan/plan_explain.cpp index 2bb227077..e9227b657 100644 --- a/src/duckdb/src/execution/physical_plan/plan_explain.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_explain.cpp @@ -3,8 +3,8 @@ #include "duckdb/execution/operator/helper/physical_explain_analyze.hpp" #include "duckdb/execution/operator/scan/physical_column_data_scan.hpp" #include "duckdb/execution/physical_plan_generator.hpp" -#include "duckdb/main/client_context.hpp" #include "duckdb/planner/operator/logical_explain.hpp" +#include "duckdb/main/settings.hpp" namespace duckdb { @@ -21,7 +21,7 @@ PhysicalOperator &PhysicalPlanGenerator::CreatePlan(LogicalExplain &op) { // Format the plan and set the output of the EXPLAIN. op.physical_plan = plan.ToString(op.explain_format); vector keys, values; - switch (ClientConfig::GetConfig(context).explain_output_type) { + switch (Settings::Get(context)) { case ExplainOutputType::OPTIMIZED_ONLY: keys = {"logical_opt"}; values = {logical_plan_opt}; diff --git a/src/duckdb/src/execution/physical_plan/plan_insert.cpp b/src/duckdb/src/execution/physical_plan/plan_insert.cpp index ab8df5393..bc7eda78c 100644 --- a/src/duckdb/src/execution/physical_plan/plan_insert.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_insert.cpp @@ -44,7 +44,7 @@ bool PhysicalPlanGenerator::PreserveInsertionOrder(ClientContext &context, Physi return false; } // preserve insertion order - check flags - if (!DBConfig::GetSetting(context)) { + if (!Settings::Get(context)) { // preserving insertion order is disabled by config return false; } diff --git a/src/duckdb/src/execution/physical_plan/plan_recursive_cte.cpp b/src/duckdb/src/execution/physical_plan/plan_recursive_cte.cpp index 9e75d3c5c..98513cf59 100644 --- a/src/duckdb/src/execution/physical_plan/plan_recursive_cte.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_recursive_cte.cpp @@ -26,10 +26,14 @@ PhysicalOperator &PhysicalPlanGenerator::CreatePlan(LogicalRecursiveCTE &op) { // If the logical operator has no key targets or all columns are referenced, // then we create a normal recursive CTE operator. if (op.key_targets.empty()) { + auto recurring_table = make_shared_ptr(context, op.types); + recurring_cte_tables[op.table_index] = recurring_table; auto &right = CreatePlan(*op.children[1]); auto &cte = Make(op.ctename, op.table_index, op.types, op.union_all, left, right, op.estimated_cardinality); auto &cast_cte = cte.Cast(); + cast_cte.ref_recurring = op.ref_recurring; + cast_cte.recurring_table = recurring_table; cast_cte.distinct_types = op.types; cast_cte.working_table = working_table; return cte; diff --git a/src/duckdb/src/execution/physical_plan/plan_set_operation.cpp b/src/duckdb/src/execution/physical_plan/plan_set_operation.cpp index ee71c5509..cf4796d14 100644 --- a/src/duckdb/src/execution/physical_plan/plan_set_operation.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_set_operation.cpp @@ -1,4 +1,5 @@ #include "duckdb/execution/physical_plan_generator.hpp" + #include "duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp" #include "duckdb/execution/operator/aggregate/physical_window.hpp" #include "duckdb/execution/operator/join/physical_hash_join.hpp" @@ -6,11 +7,13 @@ #include "duckdb/execution/operator/set/physical_union.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/expression/bound_window_expression.hpp" +#include "duckdb/planner/expression_binder.hpp" #include "duckdb/planner/operator/logical_set_operation.hpp" namespace duckdb { -static vector> CreatePartitionedRowNumExpression(const vector &types) { +static vector> CreatePartitionedRowNumExpression(ClientContext &client, + const vector &types) { vector> res; auto expr = make_uniq(ExpressionType::WINDOW_ROW_NUMBER, LogicalType::BIGINT, nullptr, nullptr); @@ -18,6 +21,7 @@ static vector> CreatePartitionedRowNumExpression(const ve expr->end = WindowBoundary::UNBOUNDED_FOLLOWING; for (idx_t i = 0; i < types.size(); i++) { expr->partitions.push_back(make_uniq(types[i], i)); + ExpressionBinder::PushCollation(client, expr->partitions.back(), types[i]); } res.push_back(std::move(expr)); return res; @@ -71,13 +75,13 @@ PhysicalOperator &PhysicalPlanGenerator::CreatePlan(LogicalSetOperation &op) { vector window_types = types; window_types.push_back(LogicalType::BIGINT); - auto select_list = CreatePartitionedRowNumExpression(types); + auto select_list = CreatePartitionedRowNumExpression(context, types); auto &left_window = Make(window_types, std::move(select_list), left.get().estimated_cardinality); left_window.children.push_back(left); left = left_window; - select_list = CreatePartitionedRowNumExpression(types); + select_list = CreatePartitionedRowNumExpression(context, types); auto &right_window = Make(window_types, std::move(select_list), right.get().estimated_cardinality); right_window.children.push_back(right); diff --git a/src/duckdb/src/execution/physical_plan_generator.cpp b/src/duckdb/src/execution/physical_plan_generator.cpp index 30a28ea70..c5d583bec 100644 --- a/src/duckdb/src/execution/physical_plan_generator.cpp +++ b/src/duckdb/src/execution/physical_plan_generator.cpp @@ -57,7 +57,7 @@ unique_ptr PhysicalPlanGenerator::PlanInternal(LogicalOperator &op physical_plan->SetRoot(CreatePlan(op)); physical_plan->Root().estimated_cardinality = op.estimated_cardinality; - auto debug_verify_vector = DBConfig::GetSetting(context); + auto debug_verify_vector = Settings::Get(context); if (debug_verify_vector != DebugVectorVerification::NONE) { if (debug_verify_vector != DebugVectorVerification::DICTIONARY_EXPRESSION && debug_verify_vector != DebugVectorVerification::VARIANT_VECTOR) { diff --git a/src/duckdb/src/function/aggregate/distributive/first_last_any.cpp b/src/duckdb/src/function/aggregate/distributive/first_last_any.cpp index 0eed72d84..2b6b3bdf8 100644 --- a/src/duckdb/src/function/aggregate/distributive/first_last_any.cpp +++ b/src/duckdb/src/function/aggregate/distributive/first_last_any.cpp @@ -1,5 +1,4 @@ #include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/function/aggregate/distributive_functions.hpp" #include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/function/create_sort_key.hpp" @@ -222,16 +221,38 @@ template void FirstFunctionSimpleUpdate(Vector inputs[], AggregateInputData &aggregate_input_data, idx_t input_count, data_ptr_t state, idx_t count) { auto agg_state = reinterpret_cast *>(state); - if (LAST || !agg_state->is_set) { + if (LAST) { + // For LAST, iterate backward within each batch to find the last value + // This saves iterating through all elements when we only need the last one + D_ASSERT(input_count == 1); + UnifiedVectorFormat idata; + inputs[0].ToUnifiedFormat(count, idata); + auto input_data = UnifiedVectorFormat::GetData(idata); + + for (idx_t i = count; i-- > 0;) { + const auto idx = idata.sel->get_index(i); + const auto row_valid = idata.validity.RowIsValid(idx); + if (SKIP_NULLS && !row_valid) { + continue; + } + // Found the last value in this batch - update state and exit + agg_state->is_set = true; + agg_state->is_null = !row_valid; + if (row_valid) { + agg_state->value = input_data[idx]; + } + break; + } + // If we get here with SKIP_NULLS, all values were NULL - keep previous state + } else if (!agg_state->is_set) { // For FIRST, this skips looping over the input once the aggregate state has been set - // FIXME: for LAST we could loop from the back of the Vector instead AggregateFunction::UnaryUpdate, T, FirstFunction>(inputs, aggregate_input_data, input_count, state, count); } } template -AggregateFunction GetFirstAggregateTemplated(LogicalType type) { +AggregateFunction GetFirstAggregateTemplated(const LogicalType &type) { auto result = AggregateFunction::UnaryAggregate, T, T, FirstFunction>(type, type); result.SetStateSimpleUpdateCallback(FirstFunctionSimpleUpdate); return result; diff --git a/src/duckdb/src/function/aggregate/distributive/minmax.cpp b/src/duckdb/src/function/aggregate/distributive/minmax.cpp index ce8f80aea..40c96d412 100644 --- a/src/duckdb/src/function/aggregate/distributive/minmax.cpp +++ b/src/duckdb/src/function/aggregate/distributive/minmax.cpp @@ -335,7 +335,7 @@ unique_ptr BindMinMax(ClientContext &context, AggregateFunction &f vector> &arguments) { if (arguments[0]->return_type.id() == LogicalTypeId::VARCHAR) { auto str_collation = StringType::GetCollation(arguments[0]->return_type); - if (!str_collation.empty() || !DBConfig::GetSetting(context).empty()) { + if (!str_collation.empty() || !Settings::Get(context).empty()) { // If aggr function is min/max and uses collations, replace bound_function with arg_min/arg_max // to make sure the result's correctness. string function_name = function.name == "min" ? "arg_min" : "arg_max"; diff --git a/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp b/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp index ea78de81b..9f08f7189 100644 --- a/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +++ b/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp @@ -24,7 +24,7 @@ struct SortedAggregateBindData : public FunctionData { SortedAggregateBindData(ClientContext &context, Expressions &children, AggregateFunction &aggregate, BindInfoPtr &bind_info, OrderBys &order_bys) : context(context), function(aggregate), bind_info(std::move(bind_info)), - threshold(DBConfig::GetSetting(context)) { + threshold(Settings::Get(context)) { // Describe the arguments. for (const auto &child : children) { buffered_cols.emplace_back(buffered_cols.size()); diff --git a/src/duckdb/src/function/cast/cast_function_set.cpp b/src/duckdb/src/function/cast/cast_function_set.cpp index 606fa9010..ae4ac3846 100644 --- a/src/duckdb/src/function/cast/cast_function_set.cpp +++ b/src/duckdb/src/function/cast/cast_function_set.cpp @@ -179,9 +179,9 @@ int64_t CastFunctionSet::ImplicitCastCost(optional_ptr context, c if (score < 0 && source.id() != LogicalTypeId::BLOB && target.id() == LogicalTypeId::VARCHAR) { bool old_implicit_casting = false; if (context) { - old_implicit_casting = DBConfig::GetSetting(*context); + old_implicit_casting = Settings::Get(*context); } else if (config) { - old_implicit_casting = DBConfig::GetSetting(*config); + old_implicit_casting = Settings::Get(*config); } if (old_implicit_casting) { // very high cost to avoid choosing this cast if any other option is available diff --git a/src/duckdb/src/function/cast/default_casts.cpp b/src/duckdb/src/function/cast/default_casts.cpp index 558329f70..9ee5f6957 100644 --- a/src/duckdb/src/function/cast/default_casts.cpp +++ b/src/duckdb/src/function/cast/default_casts.cpp @@ -164,6 +164,8 @@ BoundCastInfo DefaultCasts::GetDefaultCastFunction(BindCastInput &input, const L return ArrayCastSwitch(input, source, target); case LogicalTypeId::GEOMETRY: return GeoCastSwitch(input, source, target); + case LogicalTypeId::TYPE: + return TypeCastSwitch(input, source, target); case LogicalTypeId::BIGNUM: return BignumCastSwitch(input, source, target); case LogicalTypeId::AGGREGATE_STATE: diff --git a/src/duckdb/src/function/cast/geo_casts.cpp b/src/duckdb/src/function/cast/geo_casts.cpp index 29dfe75f2..35235dc1c 100644 --- a/src/duckdb/src/function/cast/geo_casts.cpp +++ b/src/duckdb/src/function/cast/geo_casts.cpp @@ -25,8 +25,8 @@ BoundCastInfo DefaultCasts::GeoCastSwitch(BindCastInput &input, const LogicalTyp // TODO: Use client context (and allow extensions) to determine if the cast is okay (crs's are equivalent) if (!source_crs.Equals(target_crs)) { - throw BinderException("Cannot cast GEOMETRY with CRS '" + source_crs.GetDisplayName() + - "' to GEOMETRY with different CRS '" + target_crs.GetDisplayName() + "'"); + throw BinderException("Cannot cast GEOMETRY with CRS '" + source_crs.GetIdentifier() + + "' to GEOMETRY with different CRS '" + target_crs.GetIdentifier() + "'"); } } // The actual data representation stays the same, so we can do a reinterpret cast diff --git a/src/duckdb/src/function/cast/list_casts.cpp b/src/duckdb/src/function/cast/list_casts.cpp index 156b43143..bf9fcea0b 100644 --- a/src/duckdb/src/function/cast/list_casts.cpp +++ b/src/duckdb/src/function/cast/list_casts.cpp @@ -98,7 +98,7 @@ static bool ListToVarcharCast(Vector &source, Vector &result, idx_t count, CastP static constexpr const idx_t SEP_LENGTH = 2; static constexpr const idx_t NULL_LENGTH = 4; unsafe_unique_array needs_quotes; - idx_t needs_quotes_length; + idx_t needs_quotes_length = DConstants::INVALID_INDEX; for (idx_t i = 0; i < count; i++) { if (!validity.RowIsValid(i)) { diff --git a/src/duckdb/src/function/cast/map_cast.cpp b/src/duckdb/src/function/cast/map_cast.cpp index ee8a4b11a..a8ea727a4 100644 --- a/src/duckdb/src/function/cast/map_cast.cpp +++ b/src/duckdb/src/function/cast/map_cast.cpp @@ -64,7 +64,7 @@ static bool MapToVarcharCast(Vector &source, Vector &result, idx_t count, CastPa auto result_data = FlatVector::GetData(result); unsafe_unique_array key_needs_quotes; unsafe_unique_array value_needs_quotes; - idx_t needs_quotes_length; + idx_t needs_quotes_length = DConstants::INVALID_INDEX; for (idx_t i = 0; i < count; i++) { if (!validity.RowIsValid(i)) { FlatVector::SetNull(result, i, true); diff --git a/src/duckdb/src/function/cast/type_cast.cpp b/src/duckdb/src/function/cast/type_cast.cpp new file mode 100644 index 000000000..3984e79f1 --- /dev/null +++ b/src/duckdb/src/function/cast/type_cast.cpp @@ -0,0 +1,15 @@ +#include "duckdb/function/cast/default_casts.hpp" +#include "duckdb/function/cast/vector_cast_helpers.hpp" + +namespace duckdb { + +BoundCastInfo DefaultCasts::TypeCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target) { + // now switch on the result type + if (target == LogicalType::VARCHAR) { + // type to varchar + return BoundCastInfo(&VectorCastHelpers::StringCast); + } + return nullptr; +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/cast/variant/from_variant.cpp b/src/duckdb/src/function/cast/variant/from_variant.cpp index a70e65683..7b1a547f1 100644 --- a/src/duckdb/src/function/cast/variant/from_variant.cpp +++ b/src/duckdb/src/function/cast/variant/from_variant.cpp @@ -74,7 +74,9 @@ struct VariantBooleanConversion { static bool Convert(const VariantLogicalType type_id, uint32_t byte_offset, const_data_ptr_t value, bool &ret, const EmptyConversionPayloadFromVariant &payload, string &error) { if (type_id != VariantLogicalType::BOOL_FALSE && type_id != VariantLogicalType::BOOL_TRUE) { - error = StringUtil::Format("Can't convert from VARIANT(%s)", EnumUtil::ToString(type_id)); + if (error.empty()) { + error = StringUtil::Format("Can't convert from VARIANT(%s)", EnumUtil::ToString(type_id)); + } return false; } ret = type_id == VariantLogicalType::BOOL_TRUE; @@ -89,7 +91,9 @@ struct VariantDirectConversion { static bool Convert(const VariantLogicalType type_id, uint32_t byte_offset, const_data_ptr_t value, T &ret, const EmptyConversionPayloadFromVariant &payload, string &error) { if (type_id != TYPE_ID) { - error = StringUtil::Format("Can't convert from VARIANT(%s)", EnumUtil::ToString(type_id)); + if (error.empty()) { + error = StringUtil::Format("Can't convert from VARIANT(%s)", EnumUtil::ToString(type_id)); + } return false; } ret = Load(value + byte_offset); @@ -99,7 +103,9 @@ struct VariantDirectConversion { static bool Convert(const VariantLogicalType type_id, uint32_t byte_offset, const_data_ptr_t value, T &ret, const StringConversionPayload &payload, string &error) { if (type_id != TYPE_ID) { - error = StringUtil::Format("Can't convert from VARIANT(%s)", EnumUtil::ToString(type_id)); + if (error.empty()) { + error = StringUtil::Format("Can't convert from VARIANT(%s)", EnumUtil::ToString(type_id)); + } return false; } auto ptr = value + byte_offset; @@ -117,7 +123,9 @@ struct VariantDecimalConversion { static bool Convert(const VariantLogicalType type_id, uint32_t byte_offset, const_data_ptr_t value, T &ret, const DecimalConversionPayloadFromVariant &payload, string &error) { if (type_id != TYPE_ID) { - error = StringUtil::Format("Can't convert from VARIANT(%s)", EnumUtil::ToString(type_id)); + if (error.empty()) { + error = StringUtil::Format("Can't convert from VARIANT(%s)", EnumUtil::ToString(type_id)); + } return false; } auto ptr = value + byte_offset; @@ -203,9 +211,18 @@ static bool ConvertVariantToList(FromVariantConversionData &conversion_data, Vec child_data = reinterpret_cast(owned_child_data.get()); } - auto collection_result = - VariantUtils::CollectNestedData(conversion_data.variant, VariantLogicalType::ARRAY, sel, count, row, offset, - child_data, FlatVector::Validity(result)); + //! Initialize the validity with that of the result (in case some rows are already set to invalid, we need to + //! respect that) + auto &result_validity = FlatVector::Validity(result); + ValidityMask validity(count); + for (idx_t i = 0; i < count; i++) { + if (!result_validity.RowIsValid(offset + i)) { + validity.SetInvalid(i); + } + } + + auto collection_result = VariantUtils::CollectNestedData(conversion_data.variant, VariantLogicalType::ARRAY, sel, + count, row, offset, child_data, validity); if (!collection_result.success) { conversion_data.error = StringUtil::Format("Expected to find VARIANT(ARRAY), found VARIANT(%s) instead, can't convert", @@ -216,7 +233,7 @@ static bool ConvertVariantToList(FromVariantConversionData &conversion_data, Vec idx_t max_children = 0; for (idx_t i = 0; i < count; i++) { auto &child_data_entry = child_data[i]; - if (child_data_entry.is_null) { + if (!validity.RowIsValid(i)) { continue; } if (child_data_entry.child_count > max_children) { @@ -239,7 +256,7 @@ static bool ConvertVariantToList(FromVariantConversionData &conversion_data, Vec auto row_index = row.IsValid() ? row.GetIndex() : i; auto &child_data_entry = child_data[i]; - if (child_data_entry.is_null) { + if (!validity.RowIsValid(i)) { FlatVector::SetNull(result, offset + i, true); continue; } @@ -269,9 +286,18 @@ static bool ConvertVariantToArray(FromVariantConversionData &conversion_data, Ve child_data = reinterpret_cast(owned_child_data.get()); } - auto collection_result = - VariantUtils::CollectNestedData(conversion_data.variant, VariantLogicalType::ARRAY, sel, count, row, offset, - child_data, FlatVector::Validity(result)); + //! Initialize the validity with that of the result (in case some rows are already set to invalid, we need to + //! respect that) + auto &result_validity = FlatVector::Validity(result); + ValidityMask validity(count); + for (idx_t i = 0; i < count; i++) { + if (!result_validity.RowIsValid(offset + i)) { + validity.SetInvalid(i); + } + } + + auto collection_result = VariantUtils::CollectNestedData(conversion_data.variant, VariantLogicalType::ARRAY, sel, + count, row, offset, child_data, validity); if (!collection_result.success) { conversion_data.error = StringUtil::Format("Expected to find VARIANT(ARRAY), found VARIANT(%s) instead, can't convert", @@ -282,7 +308,7 @@ static bool ConvertVariantToArray(FromVariantConversionData &conversion_data, Ve const auto array_size = ArrayType::GetSize(result.GetType()); for (idx_t i = 0; i < count; i++) { auto &child_data_entry = child_data[i]; - if (child_data_entry.is_null) { + if (!validity.RowIsValid(i)) { continue; } if (child_data_entry.child_count != array_size) { @@ -302,7 +328,7 @@ static bool ConvertVariantToArray(FromVariantConversionData &conversion_data, Ve auto row_index = row.IsValid() ? row.GetIndex() : i; auto &child_data_entry = child_data[i]; - if (child_data_entry.is_null) { + if (!validity.RowIsValid(i)) { FlatVector::SetNull(result, offset + i, true); total_offset += array_size; continue; @@ -327,9 +353,18 @@ static bool ConvertVariantToStruct(FromVariantConversionData &conversion_data, V child_data = reinterpret_cast(owned_child_data.get()); } - auto collection_result = - VariantUtils::CollectNestedData(conversion_data.variant, VariantLogicalType::OBJECT, sel, count, row, offset, - child_data, FlatVector::Validity(result)); + //! Initialize the validity with that of the result (in case some rows are already set to invalid, we need to + //! respect that) + auto &result_validity = FlatVector::Validity(result); + ValidityMask validity(count); + for (idx_t i = 0; i < count; i++) { + if (!result_validity.RowIsValid(offset + i)) { + validity.SetInvalid(i); + } + } + + auto collection_result = VariantUtils::CollectNestedData(conversion_data.variant, VariantLogicalType::OBJECT, sel, + count, row, offset, child_data, validity); if (!collection_result.success) { conversion_data.error = StringUtil::Format("Expected to find VARIANT(OBJECT), found VARIANT(%s) instead, can't convert", @@ -338,7 +373,7 @@ static bool ConvertVariantToStruct(FromVariantConversionData &conversion_data, V } for (idx_t i = 0; i < count; i++) { - if (child_data[i].is_null) { + if (!validity.RowIsValid(i)) { FlatVector::SetNull(result, offset + i, true); } } @@ -367,7 +402,7 @@ static bool ConvertVariantToStruct(FromVariantConversionData &conversion_data, V component.lookup_mode = VariantChildLookupMode::BY_KEY; ValidityMask lookup_validity(count); VariantUtils::FindChildValues(conversion_data.variant, component, row_sel, child_values_sel, lookup_validity, - child_data, count); + child_data, validity, count); if (!lookup_validity.AllValid()) { optional_idx nested_index; for (idx_t i = 0; i < count; i++) { diff --git a/src/duckdb/src/function/compression_config.cpp b/src/duckdb/src/function/compression_config.cpp index dcd6068c4..fc968e871 100644 --- a/src/duckdb/src/function/compression_config.cpp +++ b/src/duckdb/src/function/compression_config.cpp @@ -216,9 +216,18 @@ vector> DBConfig::GetCompressionFunctions(const P return compression_functions->GetCompressionFunctions(physical_type); } -optional_ptr DBConfig::GetCompressionFunction(CompressionType type, - const PhysicalType physical_type) { +optional_ptr DBConfig::TryGetCompressionFunction(CompressionType type, + const PhysicalType physical_type) { return compression_functions->GetCompressionFunction(type, physical_type); } +reference DBConfig::GetCompressionFunction(CompressionType type, + const PhysicalType physical_type) { + auto result = TryGetCompressionFunction(type, physical_type); + if (!result) { + throw InternalException("Could not find compression function \"%s\" for physical type \"%s\"", + EnumUtil::ToString(type), EnumUtil::ToString(physical_type)); + } + return *result; +} } // namespace duckdb diff --git a/src/duckdb/src/function/copy_function.cpp b/src/duckdb/src/function/copy_function.cpp index d355449a5..8b069028b 100644 --- a/src/duckdb/src/function/copy_function.cpp +++ b/src/duckdb/src/function/copy_function.cpp @@ -37,11 +37,17 @@ vector GetCopyFunctionReturnLogicalTypes(CopyFunctionReturnType ret case CopyFunctionReturnType::CHANGED_ROWS_AND_FILE_LIST: return {LogicalType::BIGINT, LogicalType::LIST(LogicalType::VARCHAR)}; case CopyFunctionReturnType::WRITTEN_FILE_STATISTICS: - return {LogicalType::VARCHAR, + return {//! filename + LogicalType::VARCHAR, + //! count LogicalType::UBIGINT, + //! file size bytes LogicalType::UBIGINT, + //! footer size bytes LogicalType::UBIGINT, + //! column_path (potentially nested) -> map(stats_type -> value) LogicalType::MAP(LogicalType::VARCHAR, LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR)), + //! partition key -> value LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR)}; default: throw NotImplementedException("Unknown CopyFunctionReturnType"); diff --git a/src/duckdb/src/function/function_binder.cpp b/src/duckdb/src/function/function_binder.cpp index 8521dfe71..2d5b8366b 100644 --- a/src/duckdb/src/function/function_binder.cpp +++ b/src/duckdb/src/function/function_binder.cpp @@ -14,6 +14,7 @@ #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression_binder.hpp" +#include "duckdb/planner/binder.hpp" namespace duckdb { diff --git a/src/duckdb/src/function/pragma/pragma_queries.cpp b/src/duckdb/src/function/pragma/pragma_queries.cpp index 62ce195df..7f4f80bbc 100644 --- a/src/duckdb/src/function/pragma/pragma_queries.cpp +++ b/src/duckdb/src/function/pragma/pragma_queries.cpp @@ -202,7 +202,7 @@ static string PragmaDatabaseSize(ClientContext &context, const FunctionParameter } static string PragmaStorageInfo(ClientContext &context, const FunctionParameters ¶meters) { - return StringUtil::Format("SELECT * FROM pragma_storage_info('%s');", parameters.values[0].ToString()); + return StringUtil::Format("SELECT * FROM pragma_storage_info(%s);", SQLString(parameters.values[0].ToString())); } static string PragmaMetadataInfo(ClientContext &context, const FunctionParameters ¶meters) { diff --git a/src/duckdb/src/function/scalar/geometry/geometry_functions.cpp b/src/duckdb/src/function/scalar/geometry/geometry_functions.cpp index 50d529cdb..8a19c129d 100644 --- a/src/duckdb/src/function/scalar/geometry/geometry_functions.cpp +++ b/src/duckdb/src/function/scalar/geometry/geometry_functions.cpp @@ -91,6 +91,11 @@ static unique_ptr BindCRSFunctionExpression(FunctionBindExpressionIn static unique_ptr BindCRSFunction(ClientContext &context, ScalarFunction &bound_function, vector> &arguments) { + if (arguments[0]->HasParameter() || arguments[0]->return_type.id() == LogicalTypeId::SQLNULL) { + // parameter - unknown return type + return nullptr; + } + // Check if the CRS is set in the first argument bound_function.arguments[0] = arguments[0]->return_type; return nullptr; @@ -115,9 +120,17 @@ static unique_ptr SetCRSBind(ClientContext &context, ScalarFunctio const auto crs_val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]); if (!crs_val.IsNull()) { const auto &crs_str = StringValue::Get(crs_val); - // Attach the CRS to the return type - bound_function.return_type = LogicalType::GEOMETRY(crs_str); + + // Try to convert to identify + const auto lookup = CoordinateReferenceSystem::TryIdentify(context, crs_str); + if (lookup) { + bound_function.return_type = LogicalType::GEOMETRY(lookup->GetDefinition()); + } else { + // Pass on the raw string (better than nothing) + bound_function.return_type = LogicalType::GEOMETRY(crs_str); + } } + // Erase the CRS argument expression return nullptr; } diff --git a/src/duckdb/src/function/scalar/operator/arithmetic.cpp b/src/duckdb/src/function/scalar/operator/arithmetic.cpp index 83224332b..e47b59dab 100644 --- a/src/duckdb/src/function/scalar/operator/arithmetic.cpp +++ b/src/duckdb/src/function/scalar/operator/arithmetic.cpp @@ -5,6 +5,7 @@ #include "duckdb/common/operator/add.hpp" #include "duckdb/common/operator/interpolate.hpp" #include "duckdb/common/operator/multiply.hpp" +#include "duckdb/common/operator/negate.hpp" #include "duckdb/common/operator/numeric_binary_operators.hpp" #include "duckdb/common/operator/subtract.hpp" #include "duckdb/common/serializer/deserializer.hpp" @@ -531,35 +532,6 @@ ScalarFunctionSet OperatorAddFun::GetFunctions() { //===--------------------------------------------------------------------===// // - [subtract] //===--------------------------------------------------------------------===// -namespace { - -struct NegateOperator { - template - static bool CanNegate(T input) { - using Limits = NumericLimits; - return !(Limits::IsSigned() && Limits::Minimum() == input); - } - - template - static inline TR Operation(TA input) { - auto cast = (TR)input; - if (!CanNegate(cast)) { - throw OutOfRangeException("Overflow in negation of integer!"); - } - return -cast; - } -}; - -template <> -bool NegateOperator::CanNegate(float input) { - return true; -} - -template <> -bool NegateOperator::CanNegate(double input) { - return true; -} - template <> interval_t NegateOperator::Operation(interval_t input) { interval_t result; @@ -670,8 +642,6 @@ unique_ptr NegateBindStatistics(ClientContext &context, Function return stats.ToUnique(); } -} // namespace - ScalarFunction SubtractFunction::GetFunction(const LogicalType &type) { if (type.id() == LogicalTypeId::INTERVAL) { ScalarFunction func("-", {type}, type, ScalarFunction::UnaryFunction); @@ -1100,7 +1070,7 @@ scalar_function_t GetBinaryFunctionIgnoreZero(PhysicalType type) { template unique_ptr BindBinaryFloatingPoint(ClientContext &context, ScalarFunction &bound_function, vector> &arguments) { - if (DBConfig::GetSetting(context)) { + if (Settings::Get(context)) { bound_function.SetFunctionCallback(GetScalarBinaryFunction(bound_function.GetReturnType().InternalType())); } else { bound_function.SetFunctionCallback( diff --git a/src/duckdb/src/function/scalar/string/caseconvert.cpp b/src/duckdb/src/function/scalar/string/caseconvert.cpp index 0309b79f7..0a9f50f4a 100644 --- a/src/duckdb/src/function/scalar/string/caseconvert.cpp +++ b/src/duckdb/src/function/scalar/string/caseconvert.cpp @@ -30,21 +30,21 @@ template static idx_t GetResultLength(const char *input_data, idx_t input_length) { idx_t output_length = 0; for (idx_t i = 0; i < input_length;) { - if (input_data[i] & 0x80) { - // unicode - int sz = 0; - auto codepoint = Utf8Proc::UTF8ToCodepoint(input_data + i, sz); - auto converted_codepoint = - IS_UPPER ? Utf8Proc::CodepointToUpper(codepoint) : Utf8Proc::CodepointToLower(codepoint); - auto new_sz = Utf8Proc::CodepointLength(converted_codepoint); - D_ASSERT(new_sz >= 0); - output_length += UnsafeNumericCast(new_sz); - i += UnsafeNumericCast(sz); - } else { - // ascii + if (!(input_data[i] & 0x80)) { + // ASCII. output_length++; i++; + continue; } + + // UTF-8. + int sz = 0; + auto codepoint = Utf8Proc::UTF8ToCodepoint(input_data + i, sz); + auto converted = IS_UPPER ? Utf8Proc::CodepointToUpper(codepoint) : Utf8Proc::CodepointToLower(codepoint); + auto new_sz = Utf8Proc::CodepointLength(converted); + output_length += UnsafeNumericCast(new_sz); + D_ASSERT(sz != 0); + i += UnsafeNumericCast(sz); } return output_length; } diff --git a/src/duckdb/src/function/scalar/variant/variant_extract.cpp b/src/duckdb/src/function/scalar/variant/variant_extract.cpp index 118175004..05bcd6351 100644 --- a/src/duckdb/src/function/scalar/variant/variant_extract.cpp +++ b/src/duckdb/src/function/scalar/variant/variant_extract.cpp @@ -8,42 +8,21 @@ namespace duckdb { -namespace { - -struct BindData : public FunctionData { -public: - explicit BindData(const string &str); - explicit BindData(uint32_t index); - BindData(const BindData &other) = default; - -public: - unique_ptr Copy() const override; - bool Equals(const FunctionData &other) const override; - -public: - VariantPathComponent component; -}; - -} // namespace - -BindData::BindData(const string &str) : FunctionData() { - component.lookup_mode = VariantChildLookupMode::BY_KEY; - component.key = str; +VariantExtractBindData::VariantExtractBindData(const string &str) : FunctionData(), component(str) { } -BindData::BindData(uint32_t index) : FunctionData() { +VariantExtractBindData::VariantExtractBindData(uint32_t index) : FunctionData() { if (index == 0) { throw BinderException("Extracting index 0 from VARIANT(ARRAY) is invalid, indexes are 1-based"); } - component.lookup_mode = VariantChildLookupMode::BY_INDEX; - component.index = index - 1; + component = VariantPathComponent(index - 1); } -unique_ptr BindData::Copy() const { - return make_uniq(*this); +unique_ptr VariantExtractBindData::Copy() const { + return make_uniq(*this); } -bool BindData::Equals(const FunctionData &other) const { - auto &bind_data = other.Cast(); +bool VariantExtractBindData::Equals(const FunctionData &other) const { + auto &bind_data = other.Cast(); if (bind_data.component.lookup_mode != component.lookup_mode) { return false; } @@ -68,62 +47,26 @@ static bool GetConstantArgument(ClientContext &context, Expression &expr, Value return false; } -optional_ptr FindShreddedStats(const BaseStatistics &shredded, - const VariantPathComponent &component) { - D_ASSERT(shredded.GetType().id() == LogicalTypeId::STRUCT); - D_ASSERT(StructType::GetChildTypes(shredded.GetType()).size() == 2); - - auto &typed_value_type = StructType::GetChildTypes(shredded.GetType())[1].second; - auto &typed_value_stats = StructStats::GetChildStats(shredded, 1); - switch (component.lookup_mode) { - case VariantChildLookupMode::BY_INDEX: { - if (typed_value_type.id() != LogicalTypeId::LIST) { - return nullptr; - } - auto &child_stats = ListStats::GetChildStats(typed_value_stats); - return child_stats; - } - case VariantChildLookupMode::BY_KEY: { - if (typed_value_type.id() != LogicalTypeId::STRUCT) { - return nullptr; - } - auto &object_fields = StructType::GetChildTypes(typed_value_type); - for (idx_t i = 0; i < object_fields.size(); i++) { - auto &object_field = object_fields[i]; - if (StringUtil::CIEquals(object_field.first, component.key)) { - return StructStats::GetChildStats(typed_value_stats, i); - } - } - return nullptr; - } - default: - throw InternalException("VariantChildLookupMode::%s not implemented for FindShreddedStats", - EnumUtil::ToString(component.lookup_mode)); - } -} - static unique_ptr VariantExtractPropagateStats(ClientContext &context, FunctionStatisticsInput &input) { auto &child_stats = input.child_stats; auto &bind_data = input.bind_data; - auto &info = bind_data->Cast(); + auto &info = bind_data->Cast(); auto &variant_stats = child_stats[0]; const bool is_shredded = VariantStats::IsShredded(variant_stats); if (!is_shredded) { return nullptr; } auto &shredded_stats = VariantStats::GetShreddedStats(variant_stats); - auto found_stats = FindShreddedStats(shredded_stats, info.component); - if (!found_stats) { + if (!VariantShreddedStats::IsFullyShredded(shredded_stats)) { + return nullptr; + } + auto found_stats = VariantShreddedStats::FindChildStats(shredded_stats, info.component); + if (!found_stats || !VariantShreddedStats::IsFullyShredded(*found_stats)) { return nullptr; } - auto &unshredded_stats = VariantStats::GetUnshreddedStats(variant_stats); - auto child_variant_stats = VariantStats::CreateShredded(found_stats->GetType()); - VariantStats::SetUnshreddedStats(child_variant_stats, unshredded_stats); - VariantStats::SetShreddedStats(child_variant_stats, *found_stats); - - return child_variant_stats.ToUnique(); + return VariantStats::WrapExtractedFieldAsVariant(variant_stats, *found_stats); } static unique_ptr VariantExtractBind(ClientContext &context, ScalarFunction &bound_function, @@ -143,29 +86,16 @@ static unique_ptr VariantExtractBind(ClientContext &context, Scala } if (constant_arg.type().id() == LogicalTypeId::VARCHAR) { - return make_uniq(constant_arg.GetValue()); + return make_uniq(constant_arg.GetValue()); } else if (constant_arg.type().id() == LogicalTypeId::UINTEGER) { - return make_uniq(constant_arg.GetValue()); + return make_uniq(constant_arg.GetValue()); } else { throw InternalException("Constant-folded argument was not of type UINTEGER or VARCHAR"); } } -//! FIXME: it could make sense to allow a third argument: 'default' -//! This can currently be achieved with COALESCE(TRY(), 'default') -static void VariantExtractFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto count = input.size(); - - D_ASSERT(input.ColumnCount() == 2); - auto &variant_vec = input.data[0]; - D_ASSERT(variant_vec.GetType() == LogicalType::VARIANT()); - - auto &path = input.data[1]; - D_ASSERT(path.GetVectorType() == VectorType::CONSTANT_VECTOR); - (void)path; - - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); +void VariantUtils::VariantExtract(Vector &variant_vec, const vector &components, Vector &result, + idx_t count) { auto &allocator = Allocator::DefaultAllocator(); RecursiveUnifiedVectorFormat source_format; @@ -176,58 +106,48 @@ static void VariantExtractFunction(DataChunk &input, ExpressionState &state, Vec //! Extract always starts by looking at value_index 0 SelectionVector value_index_sel; value_index_sel.Initialize(count); - for (idx_t i = 0; i < count; i++) { - value_index_sel[i] = 0; - } SelectionVector new_value_index_sel; new_value_index_sel.Initialize(count); + for (idx_t i = 0; i < count; i++) { + value_index_sel[i] = 0; + } + auto owned_nested_data = allocator.Allocate(sizeof(VariantNestedData) * count); auto nested_data = reinterpret_cast(owned_nested_data.get()); - auto &component = info.component; - auto expected_type = component.lookup_mode == VariantChildLookupMode::BY_INDEX ? VariantLogicalType::ARRAY - : VariantLogicalType::OBJECT; - auto collection_result = VariantUtils::CollectNestedData( - variant, expected_type, value_index_sel, count, optional_idx(), 0, nested_data, FlatVector::Validity(result)); - if (!collection_result.success) { - if (expected_type == VariantLogicalType::ARRAY) { - throw InvalidInputException("Can't extract index %d from a VARIANT(%s)", component.index, - EnumUtil::ToString(collection_result.wrong_type)); - } else { - D_ASSERT(expected_type == VariantLogicalType::OBJECT); - throw InvalidInputException("Can't extract key '%s' from a VARIANT(%s)", component.key, - EnumUtil::ToString(collection_result.wrong_type)); - } - } - - //! Look up the value_index of the child we're extracting - ValidityMask lookup_validity(count); - VariantUtils::FindChildValues(variant, component, nullptr, new_value_index_sel, lookup_validity, nested_data, - count); - if (!lookup_validity.AllValid()) { - optional_idx index; - for (idx_t i = 0; i < count; i++) { - if (!lookup_validity.RowIsValid(i)) { - index = i; - break; + //! Perform the extract + ValidityMask validity(count); + for (idx_t i = 0; i < components.size(); i++) { + auto &component = components[i]; + auto &input_indices = i % 2 == 0 ? value_index_sel : new_value_index_sel; + auto &output_indices = i % 2 == 0 ? new_value_index_sel : value_index_sel; + + auto expected_type = component.lookup_mode == VariantChildLookupMode::BY_INDEX ? VariantLogicalType::ARRAY + : VariantLogicalType::OBJECT; + + (void)VariantUtils::CollectNestedData(variant, expected_type, input_indices, count, optional_idx(), 0, + nested_data, validity); + //! Look up the value_index of the child we're extracting + ValidityMask lookup_validity(count); + VariantUtils::FindChildValues(variant, component, nullptr, output_indices, lookup_validity, nested_data, + validity, count); + + for (idx_t j = 0; j < count; j++) { + if (!validity.RowIsValid(j)) { + continue; + } + if (!lookup_validity.AllValid() && !lookup_validity.RowIsValid(j)) { + //! No child could be extracted, set to NULL + validity.SetInvalid(j); + continue; + } + //! Get the index into 'values' + auto type_id = variant.GetTypeId(j, output_indices[j]); + if (type_id == VariantLogicalType::VARIANT_NULL) { + validity.SetInvalid(j); } - } - D_ASSERT(index.IsValid()); - switch (component.lookup_mode) { - case VariantChildLookupMode::BY_INDEX: { - auto nested_index = index.GetIndex(); - throw InvalidInputException("VARIANT(ARRAY(%d)) is missing index %d", nested_data[nested_index].child_count, - component.index); - } - case VariantChildLookupMode::BY_KEY: { - auto nested_index = index.GetIndex(); - auto row_index = nested_index; - auto object_keys = VariantUtils::GetObjectKeys(variant, row_index, nested_data[nested_index]); - throw InvalidInputException("VARIANT(OBJECT(%s)) is missing key '%s'", StringUtil::Join(object_keys, ","), - component.key); - } } } @@ -252,18 +172,25 @@ static void VariantExtractFunction(DataChunk &input, ExpressionState &state, Vec ListVector::Reserve(result_values, values_list_size); ListVector::SetListSize(result_values, values_list_size); auto result_values_data = FlatVector::GetData(result_values); + auto &result_values_validity = FlatVector::Validity(result_values); for (idx_t i = 0; i < count; i++) { + if (!validity.RowIsValid(i)) { + result_values_validity.SetInvalid(i); + continue; + } result_values_data[i] = values_data[values.sel->get_index(i)]; } + auto &result_indices = components.size() % 2 == 0 ? value_index_sel : new_value_index_sel; + //! Prepare the selection vector to remap index 0 of each row SelectionVector new_sel(0, values_list_size); for (idx_t i = 0; i < count; i++) { - if (nested_data[i].is_null) { + if (!validity.RowIsValid(i)) { continue; } auto &list_entry = values_data[values.sel->get_index(i)]; - new_sel.set_index(list_entry.offset, list_entry.offset + new_value_index_sel[i]); + new_sel.set_index(list_entry.offset, list_entry.offset + result_indices[i]); } auto &result_type_id = VariantVector::GetValuesTypeId(result); @@ -273,17 +200,42 @@ static void VariantExtractFunction(DataChunk &input, ExpressionState &state, Vec result_byte_offset.Dictionary(VariantVector::GetValuesByteOffset(variant_vec), values_list_size, new_sel, values_list_size); - auto value_is_null = VariantUtils::ValueIsNull(variant, new_value_index_sel, count, optional_idx()); - if (!value_is_null.empty()) { - result.Flatten(count); - for (auto &i : value_is_null) { - FlatVector::SetNull(result, i, true); + if (!validity.AllValid()) { + //! Create a copy of the vector, because we used Reference before, and we now need to adjust the data + //! Which is a problem if we're still sharing the memory with 'input' + Vector other(result.GetType(), count); + VectorOperations::Copy(result, other, count, 0, 0); + result.Reference(other); + + for (idx_t i = 0; i < count; i++) { + if (!validity.RowIsValid(i)) { + FlatVector::SetNull(result, i, true); + } } } - if (input.AllConstant()) { + if (variant_vec.GetVectorType() == VectorType::CONSTANT_VECTOR) { result.SetVectorType(VectorType::CONSTANT_VECTOR); } + result.Verify(count); +} + +//! FIXME: it could make sense to allow a third argument: 'default' +//! This can currently be achieved with COALESCE(TRY(), 'default') +static void VariantExtractFunction(DataChunk &input, ExpressionState &state, Vector &result) { + auto count = input.size(); + + D_ASSERT(input.ColumnCount() == 2); + auto &variant_vec = input.data[0]; + D_ASSERT(variant_vec.GetType() == LogicalType::VARIANT()); + + auto &path = input.data[1]; + D_ASSERT(path.GetVectorType() == VectorType::CONSTANT_VECTOR); + (void)path; + + auto &func_expr = state.expr.Cast(); + auto &info = func_expr.bind_info->Cast(); + VariantUtils::VariantExtract(variant_vec, {info.component}, result, count); } ScalarFunctionSet VariantExtractFun::GetFunctions() { diff --git a/src/duckdb/src/function/scalar/variant/variant_utils.cpp b/src/duckdb/src/function/scalar/variant/variant_utils.cpp index 5160d9381..ec75966bc 100644 --- a/src/duckdb/src/function/scalar/variant/variant_utils.cpp +++ b/src/duckdb/src/function/scalar/variant/variant_utils.cpp @@ -56,7 +56,6 @@ VariantNestedData VariantUtils::DecodeNestedData(const UnifiedVariantVectorData auto ptr = data + byte_offset; VariantNestedData result; - result.is_null = false; result.child_count = VarintDecode(ptr); if (result.child_count) { result.children_idx = VarintDecode(ptr); @@ -78,14 +77,15 @@ vector VariantUtils::GetObjectKeys(const UnifiedVariantVectorData &varia void VariantUtils::FindChildValues(const UnifiedVariantVectorData &variant, const VariantPathComponent &component, optional_ptr sel, SelectionVector &res, - ValidityMask &res_validity, VariantNestedData *nested_data, idx_t count) { + ValidityMask &res_validity, const VariantNestedData *nested_data, + const ValidityMask &validity, idx_t count) { for (idx_t i = 0; i < count; i++) { auto row_index = sel ? sel->get_index(i) : i; - auto &nested_data_entry = nested_data[i]; - if (nested_data_entry.is_null) { + if (!validity.RowIsValid(i)) { continue; } + auto &nested_data_entry = nested_data[i]; if (component.lookup_mode == VariantChildLookupMode::BY_INDEX) { auto child_idx = component.index; if (child_idx >= nested_data_entry.child_count) { @@ -139,26 +139,41 @@ vector VariantUtils::ValueIsNull(const UnifiedVariantVectorData &varia VariantNestedDataCollectionResult VariantUtils::CollectNestedData(const UnifiedVariantVectorData &variant, VariantLogicalType expected_type, - const SelectionVector &sel, idx_t count, optional_idx row, idx_t offset, + const SelectionVector &value_index_sel, idx_t count, optional_idx row, idx_t offset, VariantNestedData *child_data, ValidityMask &validity) { + VariantLogicalType wrong_type = VariantLogicalType::VARIANT_NULL; for (idx_t i = 0; i < count; i++) { auto row_index = row.IsValid() ? row.GetIndex() : i; //! NOTE: the validity is assumed to be from a FlatVector - if (!variant.RowIsValid(row_index) || !validity.RowIsValid(offset + i)) { - child_data[i].is_null = true; + //! Is the input row NULL ? + if (!variant.RowIsValid(row_index) || !validity.RowIsValid(i)) { + validity.SetInvalid(i); continue; } - auto type_id = variant.GetTypeId(row_index, sel[i]); + + //! Is the variant value NULL ? + auto type_id = variant.GetTypeId(row_index, value_index_sel[i]); if (type_id == VariantLogicalType::VARIANT_NULL) { - child_data[i].is_null = true; + validity.SetInvalid(i); continue; } + //! Is the type of the VARIANT correct? if (type_id != expected_type) { - return VariantNestedDataCollectionResult(type_id); + if (wrong_type == VariantLogicalType::VARIANT_NULL) { + //! Record the type of the first row that doesn't have the expected type + wrong_type = type_id; + } + validity.SetInvalid(i); + continue; } - child_data[i] = DecodeNestedData(variant, row_index, sel[i]); + + child_data[i] = DecodeNestedData(variant, row_index, value_index_sel[i]); + } + + if (wrong_type != VariantLogicalType::VARIANT_NULL) { + return VariantNestedDataCollectionResult(wrong_type); } return VariantNestedDataCollectionResult(); } diff --git a/src/duckdb/src/function/table/arrow.cpp b/src/duckdb/src/function/table/arrow.cpp index f9d1c8657..23e672586 100644 --- a/src/duckdb/src/function/table/arrow.cpp +++ b/src/duckdb/src/function/table/arrow.cpp @@ -15,10 +15,11 @@ #include "utf8proc_wrapper.hpp" #include "duckdb/common/extra_type_info.hpp" #include "duckdb/common/arrow/schema_metadata.hpp" +#include "duckdb/main/settings.hpp" namespace duckdb { -void ArrowTableFunction::PopulateArrowTableSchema(DBConfig &config, ArrowTableSchema &arrow_table, +void ArrowTableFunction::PopulateArrowTableSchema(ClientContext &context, ArrowTableSchema &arrow_table, const ArrowSchema &arrow_schema) { vector names; // We first gather the column names and deduplicate them @@ -41,7 +42,7 @@ void ArrowTableFunction::PopulateArrowTableSchema(DBConfig &config, ArrowTableSc if (!schema.release) { throw InvalidInputException("arrow_scan: released schema passed"); } - auto arrow_type = ArrowType::GetArrowLogicalType(config, schema); + auto arrow_type = ArrowType::GetArrowLogicalType(context, schema); arrow_table.AddColumn(col_idx, std::move(arrow_type), names[col_idx]); } } @@ -78,7 +79,7 @@ unique_ptr ArrowTableFunction::ArrowScanBind(ClientContext &contex auto &data = *res; stream_factory_get_schema(reinterpret_cast(stream_factory_ptr), data.schema_root.arrow_schema); - PopulateArrowTableSchema(DBConfig::GetConfig(context), res->arrow_table, data.schema_root.arrow_schema); + PopulateArrowTableSchema(context, res->arrow_table, data.schema_root.arrow_schema); names = res->arrow_table.GetNames(); return_types = res->arrow_table.GetTypes(); res->all_types = return_types; @@ -276,10 +277,56 @@ static bool CanPushdown(const ArrowType &type) { return false; } } +static bool HasViewType(const ArrowType &type) { + auto duck_type = type.GetDuckType(); + switch (duck_type.id()) { + case LogicalTypeId::VARCHAR: + case LogicalTypeId::BLOB: + return type.GetTypeInfo().GetSizeType() == ArrowVariableSizeType::VIEW; + case LogicalTypeId::STRUCT: + case LogicalTypeId::UNION: { + const auto &struct_info = type.GetTypeInfo(); + for (idx_t i = 0; i < struct_info.ChildCount(); i++) { + if (HasViewType(struct_info.GetChild(i))) { + return true; + } + } + return false; + } + case LogicalTypeId::LIST: + case LogicalTypeId::MAP: { + const auto &list_info = type.GetTypeInfo(); + return HasViewType(list_info.GetChild()); + } + case LogicalTypeId::ARRAY: { + const auto &array_info = type.GetTypeInfo(); + return HasViewType(array_info.GetChild()); + } + default: + return false; + } +} + +static bool TableHasViewTypes(const arrow_column_map_t &column_info) { + for (const auto &col : column_info) { + if (HasViewType(*col.second)) { + return true; + } + } + return false; +} + bool ArrowTableFunction::ArrowPushdownType(const FunctionData &bind_data, idx_t col_idx) { auto &arrow_bind_data = bind_data.Cast(); const auto &column_info = arrow_bind_data.arrow_table.GetColumns(); - auto column_type = column_info.at(col_idx); + // PyArrow's array_filter kernel doesn't support string_view/binary_view types. + // The filter is applied to ALL columns in a record batch, so if any column has a + // view type, we must disable filter pushdown for the entire table. + // See https://github.com/duckdb/duckdb-python/issues/227 + if (TableHasViewTypes(column_info)) { + return false; + } + const auto column_type = column_info.at(col_idx); return CanPushdown(*column_type); } diff --git a/src/duckdb/src/function/table/arrow/arrow_duck_schema.cpp b/src/duckdb/src/function/table/arrow/arrow_duck_schema.cpp index ddfc11b4b..1f44379df 100644 --- a/src/duckdb/src/function/table/arrow/arrow_duck_schema.cpp +++ b/src/duckdb/src/function/table/arrow/arrow_duck_schema.cpp @@ -212,23 +212,24 @@ unique_ptr ArrowType::GetTypeFromFormat(string &format) { return nullptr; } -unique_ptr ArrowType::GetTypeFromFormat(DBConfig &config, ArrowSchema &schema, string &format) { +unique_ptr ArrowType::GetTypeFromFormat(ClientContext &context, ArrowSchema &schema, string &format) { auto type = GetTypeFromFormat(format); + if (type) { return type; } if (format == "+l") { - return CreateListType(config, *schema.children[0], ArrowVariableSizeType::NORMAL, false); + return CreateListType(context, *schema.children[0], ArrowVariableSizeType::NORMAL, false); } else if (format == "+L") { - return CreateListType(config, *schema.children[0], ArrowVariableSizeType::SUPER_SIZE, false); + return CreateListType(context, *schema.children[0], ArrowVariableSizeType::SUPER_SIZE, false); } else if (format == "+vl") { - return CreateListType(config, *schema.children[0], ArrowVariableSizeType::NORMAL, true); + return CreateListType(context, *schema.children[0], ArrowVariableSizeType::NORMAL, true); } else if (format == "+vL") { - return CreateListType(config, *schema.children[0], ArrowVariableSizeType::SUPER_SIZE, true); + return CreateListType(context, *schema.children[0], ArrowVariableSizeType::SUPER_SIZE, true); } else if (format[0] == '+' && format[1] == 'w') { std::string parameters = format.substr(format.find(':') + 1); auto fixed_size = NumericCast(std::stoi(parameters)); - auto child_type = GetArrowLogicalType(config, *schema.children[0]); + auto child_type = GetArrowLogicalType(context, *schema.children[0]); auto array_type = LogicalType::ARRAY(child_type->GetDuckType(), fixed_size); auto type_info = make_uniq(std::move(child_type), fixed_size); @@ -241,7 +242,7 @@ unique_ptr ArrowType::GetTypeFromFormat(DBConfig &config, ArrowSchema "Attempted to convert a STRUCT with no fields to DuckDB which is not supported"); } for (idx_t type_idx = 0; type_idx < static_cast(schema.n_children); type_idx++) { - children.emplace_back(GetArrowLogicalType(config, *schema.children[type_idx])); + children.emplace_back(GetArrowLogicalType(context, *schema.children[type_idx])); child_types.emplace_back(schema.children[type_idx]->name, children.back()->GetDuckType()); } auto type_info = make_uniq(std::move(children)); @@ -265,7 +266,7 @@ unique_ptr ArrowType::GetTypeFromFormat(DBConfig &config, ArrowSchema for (idx_t type_idx = 0; type_idx < static_cast(schema.n_children); type_idx++) { auto type = schema.children[type_idx]; - children.emplace_back(GetArrowLogicalType(config, *type)); + children.emplace_back(GetArrowLogicalType(context, *type)); members.emplace_back(type->name, children.back()->GetDuckType()); } @@ -281,7 +282,7 @@ unique_ptr ArrowType::GetTypeFromFormat(DBConfig &config, ArrowSchema D_ASSERT(string(schema.children[1]->name) == "values"); for (idx_t i = 0; i < n_children; i++) { auto type = schema.children[i]; - children.emplace_back(GetArrowLogicalType(config, *type)); + children.emplace_back(GetArrowLogicalType(context, *type)); members.emplace_back(type->name, children.back()->GetDuckType()); } @@ -292,8 +293,8 @@ unique_ptr ArrowType::GetTypeFromFormat(DBConfig &config, ArrowSchema } else if (format == "+m") { auto &arrow_struct_type = *schema.children[0]; D_ASSERT(arrow_struct_type.n_children == 2); - auto key_type = GetArrowLogicalType(config, *arrow_struct_type.children[0]); - auto value_type = GetArrowLogicalType(config, *arrow_struct_type.children[1]); + auto key_type = GetArrowLogicalType(context, *arrow_struct_type.children[0]); + auto value_type = GetArrowLogicalType(context, *arrow_struct_type.children[1]); child_list_t key_value; key_value.emplace_back(std::make_pair("key", key_type->GetDuckType())); key_value.emplace_back(std::make_pair("value", value_type->GetDuckType())); @@ -311,9 +312,9 @@ unique_ptr ArrowType::GetTypeFromFormat(DBConfig &config, ArrowSchema throw NotImplementedException("Unsupported Internal Arrow Type %s", format); } -unique_ptr ArrowType::CreateListType(DBConfig &config, ArrowSchema &child, ArrowVariableSizeType size_type, - bool view) { - auto child_type = GetArrowLogicalType(config, child); +unique_ptr ArrowType::CreateListType(ClientContext &context, ArrowSchema &child, + ArrowVariableSizeType size_type, bool view) { + auto child_type = GetArrowLogicalType(context, child); unique_ptr type_info; auto type = LogicalType::LIST(child_type->GetDuckType()); @@ -330,9 +331,6 @@ LogicalType ArrowType::GetDuckType(bool use_dictionary) const { return dictionary_type->GetDuckType(); } if (!use_dictionary) { - if (extension_data) { - return extension_data->GetDuckDBType(); - } return type; } // Dictionaries can exist in arbitrarily nested schemas @@ -371,18 +369,15 @@ LogicalType ArrowType::GetDuckType(bool use_dictionary) const { return LogicalType::UNION(std::move(new_children)); } default: { - if (extension_data) { - return extension_data->GetDuckDBType(); - } return type; } } } -unique_ptr ArrowType::GetArrowLogicalType(DBConfig &config, ArrowSchema &schema) { - auto arrow_type = ArrowType::GetTypeFromSchema(config, schema); +unique_ptr ArrowType::GetArrowLogicalType(ClientContext &context, ArrowSchema &schema) { + auto arrow_type = ArrowType::GetTypeFromSchema(context, schema); if (schema.dictionary) { - auto dictionary = GetArrowLogicalType(config, *schema.dictionary); + auto dictionary = GetArrowLogicalType(context, *schema.dictionary); arrow_type->SetDictionary(std::move(dictionary)); } return arrow_type; @@ -402,16 +397,17 @@ ArrowArrayPhysicalType ArrowType::GetPhysicalType() const { return ArrowArrayPhysicalType::DEFAULT; } -unique_ptr ArrowType::GetTypeFromSchema(DBConfig &config, ArrowSchema &schema) { +unique_ptr ArrowType::GetTypeFromSchema(ClientContext &context, ArrowSchema &schema) { auto format = string(schema.format); // Let's first figure out if this type is an extension type ArrowSchemaMetadata schema_metadata(schema.metadata); - auto arrow_type = GetTypeFromFormat(config, schema, format); + auto &config = DBConfig::GetConfig(context); + auto arrow_type = GetTypeFromFormat(context, schema, format); if (schema_metadata.HasExtension()) { auto extension_info = schema_metadata.GetExtensionInfo(string(format)); if (config.HasArrowExtension(extension_info)) { auto extension = config.GetArrowExtension(extension_info); - arrow_type = extension.GetType(schema, schema_metadata); + arrow_type = extension.GetType(context, schema, schema_metadata); arrow_type->extension_data = extension.GetTypeExtension(); } } diff --git a/src/duckdb/src/function/table/copy_csv.cpp b/src/duckdb/src/function/table/copy_csv.cpp index 1ffd6e7ee..15f82dc93 100644 --- a/src/duckdb/src/function/table/copy_csv.cpp +++ b/src/duckdb/src/function/table/copy_csv.cpp @@ -1,6 +1,7 @@ #include "duckdb/common/bind_helpers.hpp" #include "duckdb/common/csv_writer.hpp" #include "duckdb/common/file_system.hpp" +#include "duckdb/common/multi_file/multi_file_function.hpp" #include "duckdb/common/multi_file/multi_file_reader.hpp" #include "duckdb/common/serializer/memory_stream.hpp" #include "duckdb/common/serializer/write_stream.hpp" @@ -8,8 +9,8 @@ #include "duckdb/common/types/column/column_data_collection.hpp" #include "duckdb/common/types/string_type.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/execution/operator/csv_scanner/sniffer/csv_sniffer.hpp" #include "duckdb/execution/operator/csv_scanner/csv_multi_file_info.hpp" +#include "duckdb/execution/operator/csv_scanner/sniffer/csv_sniffer.hpp" #include "duckdb/function/copy_function.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/function/table/read_csv.hpp" @@ -18,8 +19,9 @@ #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/function_expression.hpp" #include "duckdb/parser/parsed_data/copy_info.hpp" +#include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" -#include "duckdb/common/multi_file/multi_file_function.hpp" +#include "duckdb/planner/expression_binder.hpp" namespace duckdb { diff --git a/src/duckdb/src/function/table/glob.cpp b/src/duckdb/src/function/table/glob.cpp index de1099258..3933a6fa4 100644 --- a/src/duckdb/src/function/table/glob.cpp +++ b/src/duckdb/src/function/table/glob.cpp @@ -41,6 +41,7 @@ static void GlobFunction(ClientContext &context, TableFunctionInput &data_p, Dat auto &bind_data = data_p.bind_data->Cast(); auto &state = data_p.global_state->Cast(); + state.file_list_scan.scan_type = MultiFileListScanType::ALWAYS_FETCH; idx_t count = 0; while (count < STANDARD_VECTOR_SIZE) { OpenFileInfo file; @@ -48,6 +49,7 @@ static void GlobFunction(ClientContext &context, TableFunctionInput &data_p, Dat break; } output.data[0].SetValue(count++, file.path); + state.file_list_scan.scan_type = MultiFileListScanType::FETCH_IF_AVAILABLE; } output.SetCardinality(count); } diff --git a/src/duckdb/src/function/table/read_file.cpp b/src/duckdb/src/function/table/read_file.cpp index ec9fd8260..30b5cc896 100644 --- a/src/duckdb/src/function/table/read_file.cpp +++ b/src/duckdb/src/function/table/read_file.cpp @@ -170,7 +170,6 @@ FileGlobInput DirectMultiFileInfo::GetGlobInput() { struct ReadBlobOperation { static constexpr const char *NAME = "read_blob"; - static constexpr const char *FILE_TYPE = "blob"; static inline LogicalType TYPE() { return LogicalType::BLOB; @@ -179,7 +178,6 @@ struct ReadBlobOperation { struct ReadTextOperation { static constexpr const char *NAME = "read_text"; - static constexpr const char *FILE_TYPE = "text"; static inline LogicalType TYPE() { return LogicalType::VARCHAR; diff --git a/src/duckdb/src/function/table/sniff_csv.cpp b/src/duckdb/src/function/table/sniff_csv.cpp index 7b133bccd..f428d77b3 100644 --- a/src/duckdb/src/function/table/sniff_csv.cpp +++ b/src/duckdb/src/function/table/sniff_csv.cpp @@ -133,9 +133,9 @@ static void CSVSniffFunction(ClientContext &context, TableFunctionInput &data_p, return; } const CSVSniffFunctionData &data = data_p.bind_data->Cast(); - auto &fs = duckdb::FileSystem::GetFileSystem(context); - auto files = fs.GlobFiles(data.path, context, FileGlobOptions::DISALLOW_EMPTY); + auto &fs = FileSystem::GetFileSystem(context); + auto files = fs.GlobFiles(data.path, FileGlobOptions::DISALLOW_EMPTY); if (files.size() > 1) { throw NotImplementedException("sniff_csv does not operate on more than one file yet"); } diff --git a/src/duckdb/src/function/table/system/duckdb_columns.cpp b/src/duckdb/src/function/table/system/duckdb_columns.cpp index ff14fdd73..621920ba7 100644 --- a/src/duckdb/src/function/table/system/duckdb_columns.cpp +++ b/src/duckdb/src/function/table/system/duckdb_columns.cpp @@ -7,6 +7,8 @@ #include "duckdb/main/client_context.hpp" #include "duckdb/main/client_data.hpp" #include "duckdb/parser/constraints/not_null_constraint.hpp" +#include "duckdb/planner/binder.hpp" +#include "duckdb/main/query_result.hpp" #include @@ -94,7 +96,7 @@ static unique_ptr DuckDBColumnsInit(ClientContext &con class ColumnHelper { public: - static unique_ptr Create(CatalogEntry &entry); + static unique_ptr Create(ClientContext &context, CatalogEntry &entry); virtual ~ColumnHelper() { } @@ -156,20 +158,24 @@ class TableColumnHelper : public ColumnHelper { class ViewColumnHelper : public ColumnHelper { public: - explicit ViewColumnHelper(ViewCatalogEntry &entry) : entry(entry) { + explicit ViewColumnHelper(ClientContext &context, ViewCatalogEntry &entry) : entry(entry) { + entry.BindView(context); + view_columns = entry.GetColumnInfo(); + column_names = view_columns->names; + QueryResult::DeduplicateColumns(column_names); } StandardEntry &Entry() override { return entry; } idx_t NumColumns() override { - return entry.types.size(); + return view_columns->types.size(); } const string &ColumnName(idx_t col) override { - return col < entry.aliases.size() ? entry.aliases[col] : entry.names[col]; + return col < entry.aliases.size() ? entry.aliases[col] : column_names[col]; } const LogicalType &ColumnType(idx_t col) override { - return entry.types[col]; + return view_columns->types[col]; } const Value ColumnDefault(idx_t col) override { return Value(); @@ -178,23 +184,21 @@ class ViewColumnHelper : public ColumnHelper { return true; } const Value ColumnComment(idx_t col) override { - if (entry.column_comments.empty()) { - return Value(); - } - D_ASSERT(entry.column_comments.size() == entry.types.size()); - return entry.column_comments[col]; + return entry.GetColumnComment(col); } private: ViewCatalogEntry &entry; + shared_ptr view_columns; + vector column_names; }; -unique_ptr ColumnHelper::Create(CatalogEntry &entry) { +unique_ptr ColumnHelper::Create(ClientContext &context, CatalogEntry &entry) { switch (entry.type) { case CatalogType::TABLE_ENTRY: return make_uniq(entry.Cast()); case CatalogType::VIEW_ENTRY: - return make_uniq(entry.Cast()); + return make_uniq(context, entry.Cast()); default: throw NotImplementedException({{"catalog_type", CatalogTypeToString(entry.type)}}, "Unsupported catalog type for duckdb_columns"); @@ -318,7 +322,7 @@ static void DuckDBColumnsFunction(ClientContext &context, TableFunctionInput &da idx_t column_offset = data.column_offset; idx_t index = 0; while (next < data.entries.size() && index < STANDARD_VECTOR_SIZE) { - auto column_helper = ColumnHelper::Create(data.entries[next].get()); + auto column_helper = ColumnHelper::Create(context, data.entries[next].get()); idx_t columns = column_helper->NumColumns(); // Check to see if we are going to exceed the maximum index for a DataChunk diff --git a/src/duckdb/src/function/table/system/duckdb_coordinate_systems.cpp b/src/duckdb/src/function/table/system/duckdb_coordinate_systems.cpp new file mode 100644 index 000000000..3a41af07f --- /dev/null +++ b/src/duckdb/src/function/table/system/duckdb_coordinate_systems.cpp @@ -0,0 +1,124 @@ +#include "duckdb/function/table/system_functions.hpp" + +#include "duckdb/catalog/catalog.hpp" +#include "duckdb/catalog/catalog_entry/coordinate_system_catalog_entry.hpp" +#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" +#include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" +#include "duckdb/common/enum_util.hpp" +#include "duckdb/common/exception.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/main/client_data.hpp" + +namespace duckdb { + +struct DuckDBCoordinateSystemsData : public GlobalTableFunctionState { + DuckDBCoordinateSystemsData() : offset(0) { + } + + vector> entries; + idx_t offset; + unordered_set oids; +}; + +static unique_ptr DuckDBCoordinateSystemsBind(ClientContext &context, TableFunctionBindInput &input, + vector &return_types, vector &names) { + names.emplace_back("database_name"); + return_types.emplace_back(LogicalType::VARCHAR); + + names.emplace_back("database_oid"); + return_types.emplace_back(LogicalType::BIGINT); + + names.emplace_back("schema_name"); + return_types.emplace_back(LogicalType::VARCHAR); + + names.emplace_back("schema_oid"); + return_types.emplace_back(LogicalType::BIGINT); + + names.emplace_back("crs_oid"); + return_types.emplace_back(LogicalType::BIGINT); + + names.emplace_back("crs_name"); + return_types.emplace_back(LogicalType::VARCHAR); + + names.emplace_back("auth_name"); + return_types.emplace_back(LogicalType::VARCHAR); + + names.emplace_back("auth_code"); + return_types.emplace_back(LogicalType::VARCHAR); + + names.emplace_back("projjson"); + return_types.emplace_back(LogicalType::VARCHAR); + + names.emplace_back("wkt2_2019"); + return_types.emplace_back(LogicalType::VARCHAR); + + return nullptr; +} + +static unique_ptr DuckDBCoordinateSystemsInit(ClientContext &context, + TableFunctionInitInput &input) { + auto result = make_uniq(); + auto schemas = Catalog::GetAllSchemas(context); + for (auto &schema : schemas) { + schema.get().Scan(context, CatalogType::COORDINATE_SYSTEM_ENTRY, [&](CatalogEntry &entry) { + result->entries.push_back(entry.Cast()); + }); + }; + return std::move(result); +} + +static void DuckDBCoordinateSystemsFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { + auto &data = data_p.global_state->Cast(); + if (data.offset >= data.entries.size()) { + // finished returning values + return; + } + // start returning values + // either fill up the chunk or return all the remaining columns + idx_t count = 0; + while (data.offset < data.entries.size() && count < STANDARD_VECTOR_SIZE) { + auto &crs_entry = data.entries[data.offset++].get(); + + // return values: + idx_t col = 0; + // database_name, VARCHAR + output.SetValue(col++, count, crs_entry.catalog.GetName()); + // database_oid, BIGINT + output.SetValue(col++, count, Value::BIGINT(NumericCast(crs_entry.catalog.GetOid()))); + // schema_name, LogicalType::VARCHAR + output.SetValue(col++, count, Value(crs_entry.schema.name)); + // schema_oid, LogicalType::BIGINT + output.SetValue(col++, count, Value::BIGINT(NumericCast(crs_entry.schema.oid))); + // crs_oid, BIGINT + int64_t oid = NumericCast(crs_entry.oid); + Value oid_val; + if (data.oids.find(oid) == data.oids.end()) { + data.oids.insert(oid); + oid_val = Value::BIGINT(oid); + } else { + oid_val = Value(); + } + + output.SetValue(col++, count, oid_val); + // crs_name, VARCHAR + output.SetValue(col++, count, Value(crs_entry.name)); + // auth_name, VARCHAR + output.SetValue(col++, count, Value(crs_entry.authority)); + // auth_code, VARCHAR + output.SetValue(col++, count, Value(crs_entry.code)); + // projjson, VARCHAR + output.SetValue(col++, count, Value(crs_entry.projjson_definition)); + // wkt2_2019, VARCHAR + output.SetValue(col++, count, Value(crs_entry.wkt2_2019_definition)); + + count++; + } + output.SetCardinality(count); +} + +void DuckDBCoordinateSystemsFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction(TableFunction("duckdb_coordinate_systems", {}, DuckDBCoordinateSystemsFunction, + DuckDBCoordinateSystemsBind, DuckDBCoordinateSystemsInit)); +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/table/system/duckdb_log_contexts.cpp b/src/duckdb/src/function/table/system/duckdb_log_contexts.cpp index c3ec4f39a..d48b8debb 100644 --- a/src/duckdb/src/function/table/system/duckdb_log_contexts.cpp +++ b/src/duckdb/src/function/table/system/duckdb_log_contexts.cpp @@ -3,10 +3,11 @@ #include "duckdb/catalog/catalog.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" #include "duckdb/common/exception.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/main/client_data.hpp" #include "duckdb/logging/log_manager.hpp" #include "duckdb/logging/log_storage.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/main/client_data.hpp" +#include "duckdb/parser/tableref.hpp" namespace duckdb { diff --git a/src/duckdb/src/function/table/system/duckdb_secrets.cpp b/src/duckdb/src/function/table/system/duckdb_secrets.cpp index ae7f3104a..29365b3e9 100644 --- a/src/duckdb/src/function/table/system/duckdb_secrets.cpp +++ b/src/duckdb/src/function/table/system/duckdb_secrets.cpp @@ -1,12 +1,8 @@ #include "duckdb/function/table/system_functions.hpp" -#include "duckdb/common/file_system.hpp" -#include "duckdb/common/map.hpp" -#include "duckdb/common/string_util.hpp" #include "duckdb/function/function_set.hpp" #include "duckdb/main/client_context.hpp" -#include "duckdb/main/database.hpp" -#include "duckdb/main/extension_helper.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/main/secret/secret_manager.hpp" namespace duckdb { @@ -47,8 +43,7 @@ static unique_ptr DuckDBSecretsBind(ClientContext &context, TableF } } - if (!DBConfig::GetConfig(context).options.allow_unredacted_secrets && - result->redact == SecretDisplayType::UNREDACTED) { + if (!Settings::Get(context) && result->redact == SecretDisplayType::UNREDACTED) { throw InvalidInputException("Displaying unredacted secrets is disabled"); } diff --git a/src/duckdb/src/function/table/system/duckdb_settings.cpp b/src/duckdb/src/function/table/system/duckdb_settings.cpp index 9908854bd..75da7b495 100644 --- a/src/duckdb/src/function/table/system/duckdb_settings.cpp +++ b/src/duckdb/src/function/table/system/duckdb_settings.cpp @@ -91,7 +91,7 @@ unique_ptr DuckDBSettingsInit(ClientContext &context, } result->settings.push_back(std::move(value)); } - for (auto &ext_param : config.extension_parameters) { + for (auto &ext_param : config.GetExtensionSettings()) { Value setting_val; auto scope = SettingScope::GLOBAL; auto lookup_result = context.TryGetCurrentSetting(ext_param.first, setting_val); diff --git a/src/duckdb/src/function/table/system/duckdb_views.cpp b/src/duckdb/src/function/table/system/duckdb_views.cpp index 1ae6fcce7..c28b836e9 100644 --- a/src/duckdb/src/function/table/system/duckdb_views.cpp +++ b/src/duckdb/src/function/table/system/duckdb_views.cpp @@ -14,6 +14,7 @@ struct DuckDBViewsData : public GlobalTableFunctionState { } vector> entries; + vector column_ids; idx_t offset; }; @@ -67,6 +68,7 @@ unique_ptr DuckDBViewsInit(ClientContext &context, Tab schema.get().Scan(context, CatalogType::VIEW_ENTRY, [&](CatalogEntry &entry) { result->entries.push_back(entry); }); }; + result->column_ids = input.column_indexes; return std::move(result); } @@ -87,40 +89,74 @@ void DuckDBViewsFunction(ClientContext &context, TableFunctionInput &data_p, Dat } auto &view = entry.Cast(); - // return values: - idx_t col = 0; - // database_name, VARCHAR - output.SetValue(col++, count, view.catalog.GetName()); - // database_oid, BIGINT - output.SetValue(col++, count, Value::BIGINT(NumericCast(view.catalog.GetOid()))); - // schema_name, LogicalType::VARCHAR - output.SetValue(col++, count, Value(view.schema.name)); - // schema_oid, LogicalType::BIGINT - output.SetValue(col++, count, Value::BIGINT(NumericCast(view.schema.oid))); - // view_name, LogicalType::VARCHAR - output.SetValue(col++, count, Value(view.name)); - // view_oid, LogicalType::BIGINT - output.SetValue(col++, count, Value::BIGINT(NumericCast(view.oid))); - // comment, LogicalType::VARCHARs - output.SetValue(col++, count, Value(view.comment)); - // tags, LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR) - output.SetValue(col++, count, Value::MAP(view.tags)); - // internal, LogicalType::BOOLEAN - output.SetValue(col++, count, Value::BOOLEAN(view.internal)); - // temporary, LogicalType::BOOLEAN - output.SetValue(col++, count, Value::BOOLEAN(view.temporary)); - // column_count, LogicalType::BIGINT - output.SetValue(col++, count, Value::BIGINT(NumericCast(view.types.size()))); - // sql, LogicalType::VARCHAR - output.SetValue(col++, count, Value(view.ToSQL())); - + for (idx_t c = 0; c < data.column_ids.size(); c++) { + auto column_id = data.column_ids[c].GetPrimaryIndex(); + switch (column_id) { + case 0: + // database_name, VARCHAR + output.SetValue(c, count, view.catalog.GetName()); + break; + case 1: + // database_oid, BIGINT + output.SetValue(c, count, Value::BIGINT(NumericCast(view.catalog.GetOid()))); + break; + case 2: + // schema_name, LogicalType::VARCHAR + output.SetValue(c, count, Value(view.schema.name)); + break; + case 3: + // schema_oid, LogicalType::BIGINT + output.SetValue(c, count, Value::BIGINT(NumericCast(view.schema.oid))); + break; + case 4: + // view_name, LogicalType::VARCHAR + output.SetValue(c, count, Value(view.name)); + break; + case 5: + // view_oid, LogicalType::BIGINT + output.SetValue(c, count, Value::BIGINT(NumericCast(view.oid))); + break; + case 6: + // comment, LogicalType::VARCHARs + output.SetValue(c, count, Value(view.comment)); + break; + case 7: + // tags, LogicalType::MAP(LogicalType::VARCHAR, LogicalType::VARCHAR) + output.SetValue(c, count, Value::MAP(view.tags)); + break; + case 8: + // internal, LogicalType::BOOLEAN + output.SetValue(c, count, Value::BOOLEAN(view.internal)); + break; + case 9: + // temporary, LogicalType::BOOLEAN + output.SetValue(c, count, Value::BOOLEAN(view.temporary)); + break; + case 10: { + // column_count, LogicalType::BIGINT + // make sure the view is bound so we know the columns it emits + view.BindView(context); + auto columns = view.GetColumnInfo(); + output.SetValue(c, count, Value::BIGINT(NumericCast(columns->types.size()))); + break; + } + case 11: + // sql, LogicalType::VARCHAR + output.SetValue(c, count, Value(view.ToSQL())); + break; + default: + throw InternalException("Unsupported column index for duckdb_views"); + } + } count++; } output.SetCardinality(count); } void DuckDBViewsFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(TableFunction("duckdb_views", {}, DuckDBViewsFunction, DuckDBViewsBind, DuckDBViewsInit)); + TableFunction duckdb_views("duckdb_views", {}, DuckDBViewsFunction, DuckDBViewsBind, DuckDBViewsInit); + duckdb_views.projection_pushdown = true; + set.AddFunction(std::move(duckdb_views)); } } // namespace duckdb diff --git a/src/duckdb/src/function/table/system/enable_profiling.cpp b/src/duckdb/src/function/table/system/enable_profiling.cpp index a7a8cdac2..2aec20fde 100644 --- a/src/duckdb/src/function/table/system/enable_profiling.cpp +++ b/src/duckdb/src/function/table/system/enable_profiling.cpp @@ -64,8 +64,6 @@ static unique_ptr BindEnableProfiling(ClientContext &context, Tabl auto bind_data = make_uniq(); - auto config = ClientConfig::GetConfig(context); - bool metrics_set = false; for (const auto &named_param : input.named_parameters) { @@ -78,7 +76,7 @@ static unique_ptr BindEnableProfiling(ClientContext &context, Tabl bind_data->coverage = StringUtil::Lower(named_param.second.ToString()); break; case ProfilingParameterNames::SAVE_LOCATION: - bind_data->save_location = StringUtil::Lower(named_param.second.ToString()); + bind_data->save_location = named_param.second.ToString(); break; case ProfilingParameterNames::MODE: bind_data->mode = StringUtil::Lower(named_param.second.ToString()); diff --git a/src/duckdb/src/function/table/system/pragma_table_info.cpp b/src/duckdb/src/function/table/system/pragma_table_info.cpp index 56205d900..2c490003a 100644 --- a/src/duckdb/src/function/table/system/pragma_table_info.cpp +++ b/src/duckdb/src/function/table/system/pragma_table_info.cpp @@ -247,21 +247,26 @@ static void PragmaTableInfoTable(PragmaTableOperatorData &data, TableCatalogEntr data.offset = next; } -static void PragmaTableInfoView(PragmaTableOperatorData &data, ViewCatalogEntry &view, DataChunk &output, - bool is_table_info) { - if (data.offset >= view.types.size()) { +static void PragmaTableInfoView(ClientContext &context, PragmaTableOperatorData &data, ViewCatalogEntry &view, + DataChunk &output, bool is_table_info) { + // force rebind the view to ensure the names / types are up to date + view.BindView(context, BindViewAction::FORCE_REBIND); + auto columns = view.GetColumnInfo(); + auto &view_names = columns->names; + auto &view_types = columns->types; + if (data.offset >= view_types.size()) { // finished returning values return; } // start returning values // either fill up the chunk or return all the remaining columns - idx_t next = MinValue(data.offset + STANDARD_VECTOR_SIZE, view.types.size()); + idx_t next = MinValue(data.offset + STANDARD_VECTOR_SIZE, view_types.size()); output.SetCardinality(next - data.offset); for (idx_t i = data.offset; i < next; i++) { auto index = i - data.offset; - auto type = view.types[i]; - auto &name = i < view.aliases.size() ? view.aliases[i] : view.names[i]; + auto type = view_types[i]; + auto &name = i < view.aliases.size() ? view.aliases[i] : view_names[i]; if (is_table_info) { PragmaTableInfoHelper::GetViewColumns(i, name, type, output, index); @@ -280,7 +285,7 @@ static void PragmaTableInfoFunction(ClientContext &context, TableFunctionInput & PragmaTableInfoTable(state, bind_data.entry.Cast(), output, bind_data.is_table_info); break; case CatalogType::VIEW_ENTRY: - PragmaTableInfoView(state, bind_data.entry.Cast(), output, bind_data.is_table_info); + PragmaTableInfoView(context, state, bind_data.entry.Cast(), output, bind_data.is_table_info); break; default: throw NotImplementedException("Unimplemented catalog type for pragma_table_info"); diff --git a/src/duckdb/src/function/table/system_functions.cpp b/src/duckdb/src/function/table/system_functions.cpp index b51d6cde9..912d40b93 100644 --- a/src/duckdb/src/function/table/system_functions.cpp +++ b/src/duckdb/src/function/table/system_functions.cpp @@ -22,6 +22,7 @@ void BuiltinFunctions::RegisterSQLiteFunctions() { DuckDBApproxDatabaseCountFun::RegisterFunction(*this); DuckDBColumnsFun::RegisterFunction(*this); DuckDBConstraintsFun::RegisterFunction(*this); + DuckDBCoordinateSystemsFun::RegisterFunction(*this); DuckDBDatabasesFun::RegisterFunction(*this); DuckDBFunctionsFun::RegisterFunction(*this); DuckDBKeywordsFun::RegisterFunction(*this); diff --git a/src/duckdb/src/function/table/table_scan.cpp b/src/duckdb/src/function/table/table_scan.cpp index 7e0999dea..327345a34 100644 --- a/src/duckdb/src/function/table/table_scan.cpp +++ b/src/duckdb/src/function/table/table_scan.cpp @@ -676,8 +676,8 @@ unique_ptr TableScanInitGlobal(ClientContext &context, return DuckTableScanInitGlobal(context, input, storage, bind_data); } - auto scan_percentage = DBConfig::GetSetting(context); - auto scan_max_count = DBConfig::GetSetting(context); + auto scan_percentage = Settings::Get(context); + auto scan_max_count = Settings::Get(context); auto total_rows = storage.GetTotalRows(); auto total_rows_from_percentage = LossyNumericCast(double(total_rows) * scan_percentage); @@ -688,16 +688,19 @@ unique_ptr TableScanInitGlobal(ClientContext &context, set row_ids; info->BindIndexes(context, ART::TYPE_NAME); - info->GetIndexes().ScanEntries([&](IndexEntry &entry) { + for (auto &entry : indexes.IndexEntries()) { auto &index = *entry.index; if (index.GetIndexType() != ART::TYPE_NAME) { - return false; + continue; } D_ASSERT(index.IsBound()); auto &art = index.Cast(); index_scan = TryScanIndex(art, entry, column_list, input, filter_set, max_count, row_ids); - return index_scan; - }); + if (index_scan) { + // found an index - break + break; + } + } if (!index_scan) { return DuckTableScanInitGlobal(context, input, storage, bind_data); @@ -823,7 +826,7 @@ static bool TableSupportsPushdownExtract(const FunctionData &bind_data_ref, cons return false; } auto column_type = column.GetType(); - if (column_type.id() != LogicalTypeId::STRUCT) { + if (column_type.id() != LogicalTypeId::STRUCT && column_type.id() != LogicalTypeId::VARIANT) { return false; } return true; diff --git a/src/duckdb/src/function/table/version/pragma_version.cpp b/src/duckdb/src/function/table/version/pragma_version.cpp index 494b967cb..7ed2f87d6 100644 --- a/src/duckdb/src/function/table/version/pragma_version.cpp +++ b/src/duckdb/src/function/table/version/pragma_version.cpp @@ -1,5 +1,5 @@ #ifndef DUCKDB_PATCH_VERSION -#define DUCKDB_PATCH_VERSION "0-dev5469" +#define DUCKDB_PATCH_VERSION "0-dev7408" #endif #ifndef DUCKDB_MINOR_VERSION #define DUCKDB_MINOR_VERSION 5 @@ -8,10 +8,10 @@ #define DUCKDB_MAJOR_VERSION 1 #endif #ifndef DUCKDB_VERSION -#define DUCKDB_VERSION "v1.5.0-dev5469" +#define DUCKDB_VERSION "v1.5.0-dev7408" #endif #ifndef DUCKDB_SOURCE_ID -#define DUCKDB_SOURCE_ID "f5174f0d6d" +#define DUCKDB_SOURCE_ID "7f992e5a96" #endif #include "duckdb/function/table/system_functions.hpp" #include "duckdb/main/database.hpp" diff --git a/src/duckdb/src/function/table_function.cpp b/src/duckdb/src/function/table_function.cpp index db6829ce4..1290dc9ef 100644 --- a/src/duckdb/src/function/table_function.cpp +++ b/src/duckdb/src/function/table_function.cpp @@ -39,8 +39,8 @@ TableFunction::TableFunction(string name, const vector &arguments, pushdown_expression(nullptr), to_string(nullptr), dynamic_to_string(nullptr), table_scan_progress(nullptr), get_partition_data(nullptr), get_bind_info(nullptr), type_pushdown(nullptr), get_multi_file_reader(nullptr), supports_pushdown_type(nullptr), supports_pushdown_extract(nullptr), get_partition_info(nullptr), - get_partition_stats(nullptr), get_virtual_columns(nullptr), get_row_id_columns(nullptr), serialize(nullptr), - deserialize(nullptr), projection_pushdown(false), filter_pushdown(false), filter_prune(false), + get_partition_stats(nullptr), get_virtual_columns(nullptr), get_row_id_columns(nullptr), set_scan_order(nullptr), + serialize(nullptr), deserialize(nullptr), projection_pushdown(false), filter_pushdown(false), filter_prune(false), sampling_pushdown(false), late_materialization(false) { } diff --git a/src/duckdb/src/function/variant/variant_shredding.cpp b/src/duckdb/src/function/variant/variant_shredding.cpp index ee69da0e9..b3c9f3cde 100644 --- a/src/duckdb/src/function/variant/variant_shredding.cpp +++ b/src/duckdb/src/function/variant/variant_shredding.cpp @@ -156,6 +156,10 @@ void VariantShredding::WriteTypedPrimitiveValues(UnifiedVariantVectorData &varia } } +void VariantShredding::WriteMissingField(Vector &vector, idx_t index) { + FlatVector::GetData(vector)[index] = 0; +} + void VariantShredding::WriteTypedObjectValues(UnifiedVariantVectorData &variant, Vector &result, const SelectionVector &sel, const SelectionVector &value_index_sel, const SelectionVector &result_sel, idx_t count) { @@ -198,8 +202,9 @@ void VariantShredding::WriteTypedObjectValues(UnifiedVariantVectorData &variant, path_component.key = key; ValidityMask lookup_validity(count); + ValidityMask all_valid_validity(count); VariantUtils::FindChildValues(variant, path_component, sel, child_values_indexes, lookup_validity, - nested_data.get(), count); + nested_data.get(), all_valid_validity, count); if (!lookup_validity.AllValid()) { auto &child_variant_vectors = StructVector::GetEntries(child_vec); @@ -208,10 +213,10 @@ void VariantShredding::WriteTypedObjectValues(UnifiedVariantVectorData &variant, idx_t child_count = 0; for (idx_t i = 0; i < count; i++) { if (!lookup_validity.RowIsValid(i)) { - //! The field is missing, set it to null - FlatVector::SetNull(*child_variant_vectors[0], result_sel[i], true); + //! The field is missing, set the untyped value index to 0 + WriteMissingField(*child_variant_vectors[untyped_value_index], result_sel[i]); if (child_variant_vectors.size() >= 2) { - FlatVector::SetNull(*child_variant_vectors[1], result_sel[i], true); + FlatVector::SetNull(*child_variant_vectors[typed_value_index], result_sel[i], true); } continue; } diff --git a/src/duckdb/src/function/window/window_value_function.cpp b/src/duckdb/src/function/window/window_value_function.cpp index 276b99fad..e91cf7eae 100644 --- a/src/duckdb/src/function/window/window_value_function.cpp +++ b/src/duckdb/src/function/window/window_value_function.cpp @@ -194,9 +194,8 @@ unique_ptr WindowValueExecutor::GetLocalState(ExecutionContext & class WindowLeadLagGlobalState : public WindowValueGlobalState { public: - explicit WindowLeadLagGlobalState(ClientContext &client, const WindowValueExecutor &executor, - const idx_t payload_count, const ValidityMask &partition_mask, - const ValidityMask &order_mask) + WindowLeadLagGlobalState(ClientContext &client, const WindowValueExecutor &executor, const idx_t payload_count, + const ValidityMask &partition_mask, const ValidityMask &order_mask) : WindowValueGlobalState(client, executor, payload_count, partition_mask, order_mask) { if (value_tree) { use_framing = true; @@ -231,7 +230,7 @@ class WindowLeadLagGlobalState : public WindowValueGlobalState { //===--------------------------------------------------------------------===// class WindowLeadLagLocalState : public WindowValueLocalState { public: - explicit WindowLeadLagLocalState(ExecutionContext &context, const WindowLeadLagGlobalState &gstate) + WindowLeadLagLocalState(ExecutionContext &context, const WindowLeadLagGlobalState &gstate) : WindowValueLocalState(context, gstate) { if (gstate.row_tree) { local_row = gstate.row_tree->GetLocalState(context); @@ -591,8 +590,8 @@ void WindowNthValueExecutor::EvaluateInternal(ExecutionContext &context, DataChu frame_width += frame.end - frame.start; } - if (n < frame_width) { - const auto nth_index = gvstate.value_tree->SelectNth(frames, n - 1); + if (--n < frame_width) { + const auto nth_index = gvstate.value_tree->SelectNth(frames, n); if (nth_index.second || nth_index.first >= cursor.Count()) { // Past end of frame FlatVector::SetNull(result, i, true); @@ -841,8 +840,17 @@ static fill_value_t GetFillValueFunction(const LogicalType &type) { } } -WindowFillExecutor::WindowFillExecutor(BoundWindowExpression &wexpr, WindowSharedExpressions &shared) +WindowFillExecutor::WindowFillExecutor(BoundWindowExpression &wexpr, ClientContext &client, + WindowSharedExpressions &shared) : WindowValueExecutor(wexpr, shared) { + // If the argument order is prefix of the partition ordering, + // then we can just use the partition ordering. + auto &arg_orders = wexpr.arg_orders; + const auto optimize = ClientConfig::GetConfig(client).enable_optimizer; + if (optimize && BoundWindowExpression::GetSharedOrders(wexpr.orders, arg_orders) == arg_orders.size()) { + arg_order_idx.clear(); + } + // We need the sort values for interpolation, so either use the range or the secondary ordering expression if (arg_order_idx.empty()) { // We use the range ordering, even if it has not been defined @@ -871,8 +879,8 @@ static void WindowFillCopy(WindowCursor &cursor, Vector &result, idx_t count, id class WindowFillGlobalState : public WindowLeadLagGlobalState { public: - explicit WindowFillGlobalState(ClientContext &client, const WindowFillExecutor &executor, const idx_t payload_count, - const ValidityMask &partition_mask, const ValidityMask &order_mask) + WindowFillGlobalState(ClientContext &client, const WindowFillExecutor &executor, const idx_t payload_count, + const ValidityMask &partition_mask, const ValidityMask &order_mask) : WindowLeadLagGlobalState(client, executor, payload_count, partition_mask, order_mask), order_idx(executor.order_idx) { } @@ -885,6 +893,11 @@ class WindowFillLocalState : public WindowLeadLagLocalState { public: WindowFillLocalState(ExecutionContext &context, const WindowLeadLagGlobalState &gvstate) : WindowLeadLagLocalState(context, gvstate) { + // If we optimised the ordering, force computation of the validity range. + if (!gvstate.value_tree) { + state.required.insert(VALID_BEGIN); + state.required.insert(VALID_END); + } } //! Finish the sinking and prepare to scan @@ -1007,6 +1020,9 @@ void WindowFillExecutor::EvaluateInternal(ExecutionContext &context, DataChunk & if (prev_valid == DConstants::INVALID_INDEX) { // Skip to the next partition i += partition_end[i] - row_idx - 1; + if (i >= count) { + return; + } row_idx = partition_end[i] - 1; continue; } @@ -1099,7 +1115,7 @@ void WindowFillExecutor::EvaluateInternal(ExecutionContext &context, DataChunk & } } - // If there is nothing beind us (missing early value) then scan forward + // If there is nothing behind us (missing early value) then scan forward if (prev_valid == DConstants::INVALID_INDEX) { for (idx_t j = row_idx + 1; j < valid_end[i]; ++j) { if (!order_value_func(j, order_cursor)) { @@ -1116,6 +1132,9 @@ void WindowFillExecutor::EvaluateInternal(ExecutionContext &context, DataChunk & if (prev_valid == DConstants::INVALID_INDEX) { // Skip to the next partition i += partition_end[i] - row_idx - 1; + if (i >= count) { + break; + } row_idx = partition_end[i] - 1; continue; } diff --git a/src/duckdb/src/include/duckdb.h b/src/duckdb/src/include/duckdb.h index 30e240159..a9f9e79cd 100644 --- a/src/duckdb/src/include/duckdb.h +++ b/src/duckdb/src/include/duckdb.h @@ -903,7 +903,7 @@ struct duckdb_extension_access { //! Indicate that an error has occurred. void (*set_error)(duckdb_extension_info info, const char *error); //! Fetch the database on which to register the extension. - duckdb_database (*get_database)(duckdb_extension_info info); + duckdb_database *(*get_database)(duckdb_extension_info info); //! Fetch the API struct pointer. const void *(*get_api)(duckdb_extension_info info, const char *version); }; @@ -1672,6 +1672,16 @@ Get a pointer to the string data of a string_t */ DUCKDB_C_API const char *duckdb_string_t_data(duckdb_string_t *string); +/*! +Checks if a string is valid UTF-8. + +* @param str The string to check +* @param len The length of the string (in bytes) +* @return nullptr if the string is valid UTF-8. Otherwise, a duckdb_error_data containing error information. Must be +destroyed with `duckdb_destroy_error_data`. +*/ +DUCKDB_C_API duckdb_error_data duckdb_valid_utf8_check(const char *str, idx_t len); + //---------------------------------------------------------------------------------------------------------------------- // Date Time Timestamp Helpers //---------------------------------------------------------------------------------------------------------------------- @@ -2017,6 +2027,8 @@ DUCKDB_C_API duckdb_type duckdb_prepared_statement_column_type(duckdb_prepared_s /*! Binds a value to the prepared statement at the specified index. + +Supersedes all type-specific bind functions (e.g., `duckdb_bind_varchar`, `duckdb_bind_int64`, etc.). */ DUCKDB_C_API duckdb_state duckdb_bind_value(duckdb_prepared_statement prepared_statement, idx_t param_idx, duckdb_value val); @@ -2135,12 +2147,16 @@ DUCKDB_C_API duckdb_state duckdb_bind_interval(duckdb_prepared_statement prepare /*! Binds a null-terminated varchar value to the prepared statement at the specified index. + +Superseded by `duckdb_bind_value`. */ DUCKDB_C_API duckdb_state duckdb_bind_varchar(duckdb_prepared_statement prepared_statement, idx_t param_idx, const char *val); /*! Binds a varchar value to the prepared statement at the specified index. + +Superseded by `duckdb_bind_value`. */ DUCKDB_C_API duckdb_state duckdb_bind_varchar_length(duckdb_prepared_statement prepared_statement, idx_t param_idx, const char *val, idx_t length); @@ -2380,7 +2396,9 @@ Destroys the value and de-allocates all memory allocated for that type. DUCKDB_C_API void duckdb_destroy_value(duckdb_value *value); /*! -Creates a value from a null-terminated string +Creates a value from a null-terminated string. Returns nullptr if the string is not valid UTF-8 or other invalid input. + +Superseded by `duckdb_create_varchar_length`. * @param text The null-terminated string * @return The value. This must be destroyed with `duckdb_destroy_value`. @@ -2388,7 +2406,7 @@ Creates a value from a null-terminated string DUCKDB_C_API duckdb_value duckdb_create_varchar(const char *text); /*! -Creates a value from a string +Creates a value from a string. Returns nullptr if the string is not valid UTF-8 or other invalid input. * @param text The text * @param length The length of the text @@ -3457,38 +3475,44 @@ This allows NULL values to be written to the vector, regardless of whether a val DUCKDB_C_API void duckdb_vector_ensure_validity_writable(duckdb_vector vector); /*! -Safely assigns a string element in the vector at the specified location. Supersedes -`duckdb_vector_assign_string_element`. The vector type must be VARCHAR and the input must be valid UTF-8. Otherwise, it -returns an invalid Unicode error. +Assigns a string element in the vector at the specified location. For VARCHAR vectors, the input is validated as UTF-8; +if invalid, a NULL value is assigned at that index. + +Superseded by `duckdb_unsafe_vector_assign_string_element_len`, optionally combined with `duckdb_valid_utf8_check`. * @param vector The vector to alter * @param index The row position in the vector to assign the string to * @param str The null-terminated string -* @return If valid UTF-8, then `nullptr`, else error information. If not `nullptr`, then the return value must be -destroyed with `duckdb_destroy_error_data`. */ -DUCKDB_C_API duckdb_error_data duckdb_vector_safe_assign_string_element(duckdb_vector vector, idx_t index, - const char *str); +DUCKDB_C_API void duckdb_vector_assign_string_element(duckdb_vector vector, idx_t index, const char *str); /*! -Assigns a string element in the vector at the specified location. +Assigns a string element in the vector at the specified location. For VARCHAR vectors, the input is validated as UTF-8; +if invalid, a NULL value is assigned at that index. For BLOB vectors, no validation is performed. + +Superseded by `duckdb_unsafe_vector_assign_string_element_len`, optionally combined with `duckdb_valid_utf8_check`. * @param vector The vector to alter * @param index The row position in the vector to assign the string to -* @param str The null-terminated string +* @param str The string +* @param str_len The length of the string (in bytes) */ -DUCKDB_C_API void duckdb_vector_assign_string_element(duckdb_vector vector, idx_t index, const char *str); +DUCKDB_C_API void duckdb_vector_assign_string_element_len(duckdb_vector vector, idx_t index, const char *str, + idx_t str_len); /*! -Assigns a string element in the vector at the specified location. You may also use this function to assign BLOBs. +Assigns a string element in the vector at the specified location without UTF-8 validation. The caller is responsible for +ensuring the input is valid UTF-8. Use `duckdb_valid_utf8_check` to validate strings before calling this function if +needed. If the input is known to be valid UTF-8, this function can be called directly for better performance, avoiding +the overhead of redundant validation. * @param vector The vector to alter * @param index The row position in the vector to assign the string to * @param str The string * @param str_len The length of the string (in bytes) */ -DUCKDB_C_API void duckdb_vector_assign_string_element_len(duckdb_vector vector, idx_t index, const char *str, - idx_t str_len); +DUCKDB_C_API void duckdb_unsafe_vector_assign_string_element_len(duckdb_vector vector, idx_t index, const char *str, + idx_t str_len); /*! Retrieves the child vector of a list vector. diff --git a/src/duckdb/src/include/duckdb/catalog/catalog.hpp b/src/duckdb/src/include/duckdb/catalog/catalog.hpp index 9817f6c03..340a1aae9 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog.hpp @@ -38,6 +38,7 @@ struct CreateFunctionInfo; struct CreateViewInfo; struct CreateSequenceInfo; struct CreateCollationInfo; +struct CreateCoordinateSystemInfo; struct CreateIndexInfo; struct CreateTypeInfo; struct CreateTableInfo; @@ -173,6 +174,11 @@ class Catalog { //! Creates a collation in the catalog DUCKDB_API optional_ptr CreateCollation(CatalogTransaction transaction, CreateCollationInfo &info); DUCKDB_API optional_ptr CreateCollation(ClientContext &context, CreateCollationInfo &info); + //! Creates a coordinate system in the catalog + DUCKDB_API optional_ptr CreateCoordinateSystem(CatalogTransaction transaction, + CreateCoordinateSystemInfo &info); + DUCKDB_API optional_ptr CreateCoordinateSystem(ClientContext &context, + CreateCoordinateSystemInfo &info); //! Creates an index in the catalog DUCKDB_API optional_ptr CreateIndex(CatalogTransaction transaction, CreateIndexInfo &info); DUCKDB_API optional_ptr CreateIndex(ClientContext &context, CreateIndexInfo &info); @@ -202,8 +208,12 @@ class Catalog { DUCKDB_API optional_ptr CreateType(CatalogTransaction transaction, SchemaCatalogEntry &schema, CreateTypeInfo &info); //! Creates a collation in the catalog - DUCKDB_API optional_ptr CreateCollation(CatalogTransaction transaction, SchemaCatalogEntry &schema, - CreateCollationInfo &info); + DUCKDB_API static optional_ptr CreateCollation(CatalogTransaction transaction, + SchemaCatalogEntry &schema, CreateCollationInfo &info); + //! Creates a coordinate system in the catalog + DUCKDB_API static optional_ptr CreateCoordinateSystem(CatalogTransaction transaction, + SchemaCatalogEntry &schema, + CreateCoordinateSystemInfo &info); //! Drops an entry from the catalog DUCKDB_API void DropEntry(ClientContext &context, DropInfo &info); @@ -328,6 +338,7 @@ class Catalog { virtual string GetEncryptionCipher() const { return string(); } + virtual ErrorData SupportsCreateTable(BoundCreateTableInfo &info); //! Whether or not this catalog should search a specific type with the standard priority DUCKDB_API virtual CatalogLookupBehavior CatalogTypeLookupRule(CatalogType type) const { @@ -410,8 +421,8 @@ class Catalog { private: //! Lookup an entry in the schema, returning a lookup with the entry and schema if they exist - CatalogEntryLookup TryLookupEntryInternal(CatalogTransaction transaction, const string &schema, - const EntryLookupInfo &lookup_info); + virtual CatalogEntryLookup TryLookupEntryInternal(CatalogTransaction transaction, const string &schema, + const EntryLookupInfo &lookup_info); //! Calls LookupEntryInternal on the schema, trying other schemas if the schema is invalid. Sets //! CatalogEntryLookup->error depending on if_not_found when no entry is found CatalogEntryLookup TryLookupEntry(CatalogEntryRetriever &retriever, const string &schema, diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp index 925c4a076..3c8465184 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp @@ -10,11 +10,10 @@ #include "duckdb/catalog/catalog_entry/function_entry.hpp" #include "duckdb/catalog/catalog_set.hpp" -#include "duckdb/function/function.hpp" -#include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" -#include "duckdb/main/attached_database.hpp" +#include "duckdb/function/function_set.hpp" namespace duckdb { +struct CreateAggregateFunctionInfo; //! An aggregate function in the catalog class AggregateFunctionCatalogEntry : public FunctionEntry { @@ -23,13 +22,7 @@ class AggregateFunctionCatalogEntry : public FunctionEntry { static constexpr const char *Name = "aggregate function"; public: - AggregateFunctionCatalogEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateAggregateFunctionInfo &info) - : FunctionEntry(CatalogType::AGGREGATE_FUNCTION_ENTRY, catalog, schema, info), functions(info.functions) { - for (auto &function : functions.functions) { - function.catalog_name = catalog.GetAttached().GetName(); - function.schema_name = schema.name; - } - } + AggregateFunctionCatalogEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateAggregateFunctionInfo &info); //! The aggregate functions AggregateFunctionSet functions; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/coordinate_system_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/coordinate_system_catalog_entry.hpp new file mode 100644 index 000000000..f4d46db48 --- /dev/null +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/coordinate_system_catalog_entry.hpp @@ -0,0 +1,43 @@ + +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/catalog/catalog_entry/coordinate_system_catalog_entry.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/catalog/standard_entry.hpp" +#include "duckdb/parser/parsed_data/create_coordinate_system_info.hpp" + +namespace duckdb { + +//! A coordinate system catalog entry +class CoordinateSystemCatalogEntry : public StandardEntry { +public: + static constexpr const CatalogType Type = CatalogType::COORDINATE_SYSTEM_ENTRY; + static constexpr const char *Name = "coordinate system"; + +public: + CoordinateSystemCatalogEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateCoordinateSystemInfo &info) + : StandardEntry(CatalogType::COORDINATE_SYSTEM_ENTRY, schema, catalog, info.name), authority(info.authority), + code(info.code), projjson_definition(info.projjson_definition), + wkt2_2019_definition(info.wkt2_2019_definition) { + } + + //! The authority identifier of the coordinate system (e.g. "EPSG") + string authority; + + //! The code identifier of the coordinate system (e.g. "4326") + string code; + + //! The PROJJSON definition of the coordinate system + string projjson_definition; + + //! The WKT2:2019 definition of the coordinate system + string wkt2_2019_definition; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_schema_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_schema_entry.hpp index c080d0fe3..a95539fbf 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_schema_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_schema_entry.hpp @@ -9,6 +9,7 @@ #pragma once #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" +#include "duckdb/parser/parsed_data/create_coordinate_system_info.hpp" namespace duckdb { @@ -36,6 +37,8 @@ class DuckSchemaEntry : public SchemaCatalogEntry { CatalogSet collations; //! The catalog set holding the types CatalogSet types; + //! The catalog set holding the coordinate systems + CatalogSet coordinate_systems; public: optional_ptr AddEntry(CatalogTransaction transaction, unique_ptr entry, @@ -56,6 +59,8 @@ class DuckSchemaEntry : public SchemaCatalogEntry { optional_ptr CreatePragmaFunction(CatalogTransaction transaction, CreatePragmaFunctionInfo &info) override; optional_ptr CreateCollation(CatalogTransaction transaction, CreateCollationInfo &info) override; + optional_ptr CreateCoordinateSystem(CatalogTransaction transaction, + CreateCoordinateSystemInfo &info) override; optional_ptr CreateType(CatalogTransaction transaction, CreateTypeInfo &info) override; void Alter(CatalogTransaction transaction, AlterInfo &info) override; void Scan(ClientContext &context, CatalogType type, const std::function &callback) override; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/schema_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/schema_catalog_entry.hpp index 12a4ee330..a8cf62e81 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/schema_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/schema_catalog_entry.hpp @@ -26,6 +26,7 @@ struct AlterTableInfo; struct CreateIndexInfo; struct CreateFunctionInfo; struct CreateCollationInfo; +struct CreateCoordinateSystemInfo; struct CreateViewInfo; struct BoundCreateTableInfo; struct CreatePragmaFunctionInfo; @@ -80,6 +81,12 @@ class SchemaCatalogEntry : public InCatalogEntry { CreatePragmaFunctionInfo &info) = 0; //! Create a collation within the given schema virtual optional_ptr CreateCollation(CatalogTransaction transaction, CreateCollationInfo &info) = 0; + //! Create a coordiante system within the given schema + virtual optional_ptr CreateCoordinateSystem(CatalogTransaction transaction, + CreateCoordinateSystemInfo &info) { + throw NotImplementedException("Coordinate systems are not supported in schema '%s'", name); + } + //! Create a enum within the given schema virtual optional_ptr CreateType(CatalogTransaction transaction, CreateTypeInfo &info) = 0; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/view_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/view_catalog_entry.hpp index c64ffbf9e..b860ec855 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/view_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/view_catalog_entry.hpp @@ -12,12 +12,22 @@ #include "duckdb/parser/statement/select_statement.hpp" #include "duckdb/common/types.hpp" #include "duckdb/common/vector.hpp" +#include "duckdb/common/thread.hpp" +#include "duckdb/common/mutex.hpp" namespace duckdb { class DataTable; struct CreateViewInfo; +enum class ViewBindState { BOUND, BINDING, UNBOUND }; +enum class BindViewAction { BIND_IF_UNBOUND, FORCE_REBIND }; + +struct ViewColumnInfo { + vector types; + vector names; +}; + //! A view catalog entry class ViewCatalogEntry : public StandardEntry { public: @@ -34,12 +44,14 @@ class ViewCatalogEntry : public StandardEntry { string sql; //! The set of aliases associated with the view vector aliases; - //! The returned types of the view - vector types; - //! The returned names of the view - vector names; - //! The comments on the columns of the view: can be empty if there are no comments - vector column_comments; + + //! Returns the view column info, if the view is bound. Otherwise returns `nullptr` + virtual shared_ptr GetColumnInfo() const; + //! Bind a view so we know the types / names returned by it + virtual void BindView(ClientContext &context, BindViewAction action = BindViewAction::BIND_IF_UNBOUND); + //! Update the view with a new set of types / names + virtual void UpdateBinding(const vector &types, const vector &names); + Value GetColumnComment(idx_t column_index); public: unique_ptr GetInfo() const override; @@ -50,13 +62,19 @@ class ViewCatalogEntry : public StandardEntry { virtual const SelectStatement &GetQuery(); - virtual bool HasTypes() const { - // Whether or not the view has types/names defined - return true; - } - string ToSQL() const override; +private: + mutable mutex bind_lock; + //! Columns returned by the view, if bound + shared_ptr view_columns; + //! The current bind state of the view + atomic bind_state; + //! Current binding thread + atomic bind_thread; + //! The comments on the columns of the view: can be empty if there are no comments + unordered_map column_comments; + private: void Initialize(CreateViewInfo &info); }; diff --git a/src/duckdb/src/include/duckdb/catalog/default/builtin_types/types.hpp b/src/duckdb/src/include/duckdb/catalog/default/builtin_types/types.hpp deleted file mode 100644 index f3a71b594..000000000 --- a/src/duckdb/src/include/duckdb/catalog/default/builtin_types/types.hpp +++ /dev/null @@ -1,104 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/catalog/default/builtin_types/types.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is generated by scripts/generate_builtin_types.py - -#pragma once - -#include "duckdb/common/types.hpp" -#include "duckdb/common/array.hpp" - -namespace duckdb { - -struct DefaultType { - const char *name; - LogicalTypeId type; -}; - -using builtin_type_array = std::array; - -static constexpr const builtin_type_array BUILTIN_TYPES{{ - {"decimal", LogicalTypeId::DECIMAL}, - {"dec", LogicalTypeId::DECIMAL}, - {"numeric", LogicalTypeId::DECIMAL}, - {"time", LogicalTypeId::TIME}, - {"time_ns", LogicalTypeId::TIME_NS}, - {"date", LogicalTypeId::DATE}, - {"timestamp", LogicalTypeId::TIMESTAMP}, - {"datetime", LogicalTypeId::TIMESTAMP}, - {"timestamp_us", LogicalTypeId::TIMESTAMP}, - {"timestamp_ms", LogicalTypeId::TIMESTAMP_MS}, - {"timestamp_ns", LogicalTypeId::TIMESTAMP_NS}, - {"timestamp_s", LogicalTypeId::TIMESTAMP_SEC}, - {"timestamptz", LogicalTypeId::TIMESTAMP_TZ}, - {"timetz", LogicalTypeId::TIME_TZ}, - {"interval", LogicalTypeId::INTERVAL}, - {"varchar", LogicalTypeId::VARCHAR}, - {"bpchar", LogicalTypeId::VARCHAR}, - {"string", LogicalTypeId::VARCHAR}, - {"char", LogicalTypeId::VARCHAR}, - {"nvarchar", LogicalTypeId::VARCHAR}, - {"text", LogicalTypeId::VARCHAR}, - {"blob", LogicalTypeId::BLOB}, - {"bytea", LogicalTypeId::BLOB}, - {"varbinary", LogicalTypeId::BLOB}, - {"binary", LogicalTypeId::BLOB}, - {"hugeint", LogicalTypeId::HUGEINT}, - {"int128", LogicalTypeId::HUGEINT}, - {"uhugeint", LogicalTypeId::UHUGEINT}, - {"uint128", LogicalTypeId::UHUGEINT}, - {"bigint", LogicalTypeId::BIGINT}, - {"oid", LogicalTypeId::BIGINT}, - {"long", LogicalTypeId::BIGINT}, - {"int8", LogicalTypeId::BIGINT}, - {"int64", LogicalTypeId::BIGINT}, - {"ubigint", LogicalTypeId::UBIGINT}, - {"uint64", LogicalTypeId::UBIGINT}, - {"integer", LogicalTypeId::INTEGER}, - {"int", LogicalTypeId::INTEGER}, - {"int4", LogicalTypeId::INTEGER}, - {"signed", LogicalTypeId::INTEGER}, - {"integral", LogicalTypeId::INTEGER}, - {"int32", LogicalTypeId::INTEGER}, - {"uinteger", LogicalTypeId::UINTEGER}, - {"uint32", LogicalTypeId::UINTEGER}, - {"smallint", LogicalTypeId::SMALLINT}, - {"int2", LogicalTypeId::SMALLINT}, - {"short", LogicalTypeId::SMALLINT}, - {"int16", LogicalTypeId::SMALLINT}, - {"usmallint", LogicalTypeId::USMALLINT}, - {"uint16", LogicalTypeId::USMALLINT}, - {"tinyint", LogicalTypeId::TINYINT}, - {"int1", LogicalTypeId::TINYINT}, - {"utinyint", LogicalTypeId::UTINYINT}, - {"uint8", LogicalTypeId::UTINYINT}, - {"struct", LogicalTypeId::STRUCT}, - {"row", LogicalTypeId::STRUCT}, - {"list", LogicalTypeId::LIST}, - {"map", LogicalTypeId::MAP}, - {"union", LogicalTypeId::UNION}, - {"bit", LogicalTypeId::BIT}, - {"bitstring", LogicalTypeId::BIT}, - {"variant", LogicalTypeId::VARIANT}, - {"bignum", LogicalTypeId::BIGNUM}, - {"varint", LogicalTypeId::BIGNUM}, - {"boolean", LogicalTypeId::BOOLEAN}, - {"bool", LogicalTypeId::BOOLEAN}, - {"logical", LogicalTypeId::BOOLEAN}, - {"uuid", LogicalTypeId::UUID}, - {"guid", LogicalTypeId::UUID}, - {"enum", LogicalTypeId::ENUM}, - {"null", LogicalTypeId::SQLNULL}, - {"float", LogicalTypeId::FLOAT}, - {"real", LogicalTypeId::FLOAT}, - {"float4", LogicalTypeId::FLOAT}, - {"double", LogicalTypeId::DOUBLE}, - {"float8", LogicalTypeId::DOUBLE}, - {"geometry", LogicalTypeId::GEOMETRY} -}}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/default/default_coordinate_systems.hpp b/src/duckdb/src/include/duckdb/catalog/default/default_coordinate_systems.hpp new file mode 100644 index 000000000..f4125736b --- /dev/null +++ b/src/duckdb/src/include/duckdb/catalog/default/default_coordinate_systems.hpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/catalog/default/default_coordinate_systems.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/catalog/default/default_generator.hpp" +#include "duckdb/parser/parsed_data/create_macro_info.hpp" +#include "duckdb/common/array_ptr.hpp" +#include "duckdb/catalog/default/default_table_functions.hpp" + +namespace duckdb { +class SchemaCatalogEntry; + +class DefaultCoordinateSystemGenerator : public DefaultGenerator { +public: + DefaultCoordinateSystemGenerator(Catalog &catalog, SchemaCatalogEntry &schema); + + SchemaCatalogEntry &schema; + +public: + unique_ptr CreateDefaultEntry(ClientContext &context, const string &entry_name) override; + vector GetDefaultEntries() override; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/default/default_generator.hpp b/src/duckdb/src/include/duckdb/catalog/default/default_generator.hpp index 02480084a..88161f7c4 100644 --- a/src/duckdb/src/include/duckdb/catalog/default/default_generator.hpp +++ b/src/duckdb/src/include/duckdb/catalog/default/default_generator.hpp @@ -28,6 +28,12 @@ class DefaultGenerator { virtual unique_ptr CreateDefaultEntry(CatalogTransaction transaction, const string &entry_name); //! Get a list of all default entries in the generator virtual vector GetDefaultEntries() = 0; + //! Whether or not we should keep the lock while calling CreateDefaultEntry + //! If this is set to false, CreateDefaultEntry might be called multiple times in parallel also for the same entry + //! Otherwise it will be called exactly once per entry + virtual bool LockDuringCreate() const { + return false; + } }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/default/default_types.hpp b/src/duckdb/src/include/duckdb/catalog/default/default_types.hpp index 83d90982b..5d58a8299 100644 --- a/src/duckdb/src/include/duckdb/catalog/default/default_types.hpp +++ b/src/duckdb/src/include/duckdb/catalog/default/default_types.hpp @@ -22,6 +22,7 @@ class DefaultTypeGenerator : public DefaultGenerator { public: DUCKDB_API static LogicalTypeId GetDefaultType(const string &name); + DUCKDB_API static LogicalType TryDefaultBind(const string &name, const vector> ¶ms); unique_ptr CreateDefaultEntry(ClientContext &context, const string &entry_name) override; vector GetDefaultEntries() override; diff --git a/src/duckdb/src/include/duckdb/common/adbc/adbc.hpp b/src/duckdb/src/include/duckdb/common/adbc/adbc.hpp index 75532e7bf..0e2b3c309 100644 --- a/src/duckdb/src/include/duckdb/common/adbc/adbc.hpp +++ b/src/duckdb/src/include/duckdb/common/adbc/adbc.hpp @@ -129,6 +129,58 @@ AdbcStatusCode ConnectionCommit(struct AdbcConnection *connection, struct AdbcEr AdbcStatusCode ConnectionRollback(struct AdbcConnection *connection, struct AdbcError *error); +AdbcStatusCode ConnectionCancel(struct AdbcConnection *connection, struct AdbcError *error); + +// Database Typed Option API (ADBC 1.1.0) +AdbcStatusCode DatabaseGetOption(struct AdbcDatabase *database, const char *key, char *value, size_t *length, + struct AdbcError *error); +AdbcStatusCode DatabaseGetOptionBytes(struct AdbcDatabase *database, const char *key, uint8_t *value, size_t *length, + struct AdbcError *error); +AdbcStatusCode DatabaseGetOptionDouble(struct AdbcDatabase *database, const char *key, double *value, + struct AdbcError *error); +AdbcStatusCode DatabaseGetOptionInt(struct AdbcDatabase *database, const char *key, int64_t *value, + struct AdbcError *error); +AdbcStatusCode DatabaseSetOptionBytes(struct AdbcDatabase *database, const char *key, const uint8_t *value, + size_t length, struct AdbcError *error); +AdbcStatusCode DatabaseSetOptionInt(struct AdbcDatabase *database, const char *key, int64_t value, + struct AdbcError *error); +AdbcStatusCode DatabaseSetOptionDouble(struct AdbcDatabase *database, const char *key, double value, + struct AdbcError *error); + +// Connection Typed Option API (ADBC 1.1.0) +AdbcStatusCode ConnectionGetOption(struct AdbcConnection *connection, const char *key, char *value, size_t *length, + struct AdbcError *error); +AdbcStatusCode ConnectionGetOptionBytes(struct AdbcConnection *connection, const char *key, uint8_t *value, + size_t *length, struct AdbcError *error); +AdbcStatusCode ConnectionGetOptionDouble(struct AdbcConnection *connection, const char *key, double *value, + struct AdbcError *error); +AdbcStatusCode ConnectionGetOptionInt(struct AdbcConnection *connection, const char *key, int64_t *value, + struct AdbcError *error); +AdbcStatusCode ConnectionSetOptionBytes(struct AdbcConnection *connection, const char *key, const uint8_t *value, + size_t length, struct AdbcError *error); +AdbcStatusCode ConnectionSetOptionInt(struct AdbcConnection *connection, const char *key, int64_t value, + struct AdbcError *error); +AdbcStatusCode ConnectionSetOptionDouble(struct AdbcConnection *connection, const char *key, double value, + struct AdbcError *error); + +// Statement Typed Option API (ADBC 1.1.0) +AdbcStatusCode StatementGetOption(struct AdbcStatement *statement, const char *key, char *value, size_t *length, + struct AdbcError *error); +AdbcStatusCode StatementGetOptionBytes(struct AdbcStatement *statement, const char *key, uint8_t *value, size_t *length, + struct AdbcError *error); +AdbcStatusCode StatementGetOptionDouble(struct AdbcStatement *statement, const char *key, double *value, + struct AdbcError *error); +AdbcStatusCode StatementGetOptionInt(struct AdbcStatement *statement, const char *key, int64_t *value, + struct AdbcError *error); +AdbcStatusCode StatementSetOptionBytes(struct AdbcStatement *statement, const char *key, const uint8_t *value, + size_t length, struct AdbcError *error); +AdbcStatusCode StatementSetOptionInt(struct AdbcStatement *statement, const char *key, int64_t value, + struct AdbcError *error); +AdbcStatusCode StatementSetOptionDouble(struct AdbcStatement *statement, const char *key, double value, + struct AdbcError *error); + +const AdbcError *ErrorFromArrayStream(struct ArrowArrayStream *stream, AdbcStatusCode *status); + AdbcStatusCode StatementNew(struct AdbcConnection *connection, struct AdbcStatement *statement, struct AdbcError *error); @@ -137,6 +189,8 @@ AdbcStatusCode StatementRelease(struct AdbcStatement *statement, struct AdbcErro AdbcStatusCode StatementExecuteQuery(struct AdbcStatement *statement, struct ArrowArrayStream *out, int64_t *rows_affected, struct AdbcError *error); +AdbcStatusCode StatementCancel(struct AdbcStatement *statement, struct AdbcError *error); + AdbcStatusCode StatementPrepare(struct AdbcStatement *statement, struct AdbcError *error); AdbcStatusCode StatementSetSqlQuery(struct AdbcStatement *statement, const char *query, struct AdbcError *error); diff --git a/src/duckdb/src/include/duckdb/common/allocator.hpp b/src/duckdb/src/include/duckdb/common/allocator.hpp index caa7166b8..a9560de9f 100644 --- a/src/duckdb/src/include/duckdb/common/allocator.hpp +++ b/src/duckdb/src/include/duckdb/common/allocator.hpp @@ -31,6 +31,9 @@ struct PrivateAllocatorData { virtual ~PrivateAllocatorData(); AllocatorFreeType free_type = AllocatorFreeType::REQUIRES_FREE; + //! Debug info for tracking allocations. Only initialized when the Allocator is constructed in a DEBUG build. + //! Code accessing this must check for nullptr because e.g. statically-linked extensions may have a different + //! DEBUG/release configuration than the host binary. unique_ptr debug_info; template @@ -133,8 +136,12 @@ class Allocator { allocate_function_ptr_t allocate_function; free_function_ptr_t free_function; reallocate_function_ptr_t reallocate_function; - unique_ptr private_data; + + bool ShouldUseDebugInfo() const { + return private_data && private_data->free_type != AllocatorFreeType::DOES_NOT_REQUIRE_FREE && + private_data->debug_info; + } }; template diff --git a/src/duckdb/src/include/duckdb/common/arrow/arrow_type_extension.hpp b/src/duckdb/src/include/duckdb/common/arrow/arrow_type_extension.hpp index 87ccd900c..e90caf0a9 100644 --- a/src/duckdb/src/include/duckdb/common/arrow/arrow_type_extension.hpp +++ b/src/duckdb/src/include/duckdb/common/arrow/arrow_type_extension.hpp @@ -65,7 +65,8 @@ typedef void (*populate_arrow_schema_t)(DuckDBArrowSchemaHolder &root_holder, Ar const LogicalType &type, ClientContext &context, const ArrowTypeExtension &extension); -typedef unique_ptr (*get_type_t)(const ArrowSchema &schema, const ArrowSchemaMetadata &schema_metadata); +typedef unique_ptr (*get_type_t)(ClientContext &context, const ArrowSchema &schema, + const ArrowSchemaMetadata &schema_metadata); class ArrowTypeExtension { public: @@ -86,7 +87,8 @@ class ArrowTypeExtension { ArrowExtensionMetadata GetInfo() const; - unique_ptr GetType(const ArrowSchema &schema, const ArrowSchemaMetadata &schema_metadata) const; + unique_ptr GetType(ClientContext &context, const ArrowSchema &schema, + const ArrowSchemaMetadata &schema_metadata) const; shared_ptr GetTypeExtension() const; diff --git a/src/duckdb/src/include/duckdb/common/box_renderer.hpp b/src/duckdb/src/include/duckdb/common/box_renderer.hpp index 2c9d7557f..2b9e365f5 100644 --- a/src/duckdb/src/include/duckdb/common/box_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/box_renderer.hpp @@ -95,6 +95,8 @@ struct BoxRendererConfig { RenderMode render_mode = RenderMode::ROWS; //! How to render large numbers LargeNumberRendering large_number_rendering = LargeNumberRendering::NONE; + //! Hidden rows hint + string hidden_rows_hint; #ifndef DUCKDB_ASCII_TREE_RENDERER const char *LTCORNER = "\342\224\214"; // NOLINT: "┌"; diff --git a/src/duckdb/src/include/duckdb/common/column_index.hpp b/src/duckdb/src/include/duckdb/common/column_index.hpp index d1c3c672d..ea5607833 100644 --- a/src/duckdb/src/include/duckdb/common/column_index.hpp +++ b/src/duckdb/src/include/duckdb/common/column_index.hpp @@ -25,19 +25,37 @@ enum class ColumnIndexType : uint8_t { struct ColumnIndex { public: //! FIXME: this initializes the index to COLUMN_IDENTIFIER_ROW_ID (same numeric representation as INVALID_INDEX) - ColumnIndex() : index(DConstants::INVALID_INDEX), index_type(ColumnIndexType::INVALID) { + ColumnIndex() : has_index(true), index(DConstants::INVALID_INDEX), index_type(ColumnIndexType::FULL_READ) { } explicit ColumnIndex(idx_t index) - : index(index), type(LogicalType::INVALID), index_type(ColumnIndexType::FULL_READ) { + : has_index(true), index(index), type(LogicalType::INVALID), index_type(ColumnIndexType::FULL_READ) { } + explicit ColumnIndex(const string &field) + : has_index(false), field(field), type(LogicalType::INVALID), index_type(ColumnIndexType::FULL_READ) { + } + ColumnIndex(idx_t index, vector child_indexes_p) - : index(index), index_type(ColumnIndexType::FULL_READ), child_indexes(std::move(child_indexes_p)) { + : has_index(true), index(index), index_type(ColumnIndexType::FULL_READ), + child_indexes(std::move(child_indexes_p)) { + } + ColumnIndex(const string &field, vector child_indexes_p) + : has_index(false), field(field), index_type(ColumnIndexType::FULL_READ), + child_indexes(std::move(child_indexes_p)) { } inline bool operator==(const ColumnIndex &rhs) const { - if (index != rhs.index) { + if (has_index != rhs.has_index) { return false; } + if (has_index) { + if (index != rhs.index) { + return false; + } + } else { + if (field != rhs.field) { + return false; + } + } if (type != rhs.type) { return false; } @@ -66,11 +84,27 @@ struct ColumnIndex { } public: + bool HasPrimaryIndex() const { + return has_index; + } idx_t GetPrimaryIndex() const { + if (!has_index) { + throw InternalException("Attempted to get the primary index (numeric) for an index that consists of a " + "field identifier (string: %s)", + field); + } return index; } + const string &GetFieldName() const { + if (has_index) { + throw InternalException("Attempted to get the field identifier (string) for an index that consists of a " + "primary index (numeric: %d)", + index); + } + return field; + } LogicalIndex ToLogical() const { - return LogicalIndex(index); + return LogicalIndex(GetPrimaryIndex()); } bool HasChildren() const { return !child_indexes.empty(); @@ -100,23 +134,38 @@ struct ColumnIndex { void SetType(const LogicalType &type_information) { type = type_information; } - void SetPushdownExtractType(const LogicalType &type_information, optional_ptr cast_type = nullptr) { + void SetPushdownExtractType(const LogicalType &type_information, + optional_ptr cast_type = nullptr) { //! We can upgrade the optional prune hint to a PUSHDOWN_EXTRACT, which is no longer optional index_type = ColumnIndexType::PUSHDOWN_EXTRACT; type = type_information; D_ASSERT(child_indexes.size() == 1); auto &child = child_indexes[0]; - auto &child_types = StructType::GetChildTypes(type); - auto &child_type = child_types[child.GetPrimaryIndex()].second; - if (child.child_indexes.empty()) { - if (cast_type) { - child.SetType(*cast_type); + if (child.HasPrimaryIndex()) { + auto &child_types = StructType::GetChildTypes(type); + auto &child_type = child_types[child.GetPrimaryIndex()].second; + if (child.child_indexes.empty()) { + if (cast_type) { + child.SetType(*cast_type); + } else { + child.SetType(child_type); + } } else { - child.SetType(child_type); + child.SetPushdownExtractType(child_type, cast_type); } } else { - child.SetPushdownExtractType(child_type, cast_type); + D_ASSERT(type_information.id() == LogicalTypeId::VARIANT); + if (child.child_indexes.empty()) { + if (cast_type) { + child.SetType(*cast_type); + } else { + //! Without a cast, the child will always be VARIANT + child.SetType(type_information); + } + } else { + child.SetPushdownExtractType(type_information, cast_type); + } } } const LogicalType &GetScanType() const { @@ -134,12 +183,21 @@ struct ColumnIndex { this->child_indexes.push_back(std::move(new_index)); } bool IsRowIdColumn() const { + if (!has_index) { + return false; + } return index == COLUMN_IDENTIFIER_ROW_ID; } bool IsEmptyColumn() const { + if (!has_index) { + return false; + } return index == COLUMN_IDENTIFIER_EMPTY; } bool IsVirtualColumn() const { + if (!has_index) { + return false; + } return index >= VIRTUAL_COLUMN_START; } void VerifySinglePath() const { @@ -160,8 +218,20 @@ struct ColumnIndex { reference b(path); while (true) { - if (a.get().GetPrimaryIndex() != b.get().GetPrimaryIndex()) { - return false; + if (a.get().HasPrimaryIndex()) { + if (!b.get().HasPrimaryIndex()) { + return false; + } + if (a.get().GetPrimaryIndex() != b.get().GetPrimaryIndex()) { + return false; + } + } else { + if (b.get().HasPrimaryIndex()) { + return false; + } + if (a.get().GetFieldName() != b.get().GetFieldName()) { + return false; + } } const bool a_has_children = a.get().HasChildren(); const bool b_has_children = b.get().HasChildren(); @@ -187,7 +257,12 @@ struct ColumnIndex { static ColumnIndex Deserialize(Deserializer &deserializer); private: + //! The column/field index (if structured type) + bool has_index = true; idx_t index; + //! The column/field name (if semi-structured type) + string field; + //! The logical type of the column this references (if pushdown extract) LogicalType type = LogicalType::INVALID; //! The type of index, controlling how it's interpreted diff --git a/src/duckdb/src/include/duckdb/common/column_index_map.hpp b/src/duckdb/src/include/duckdb/common/column_index_map.hpp index 713351c8b..7c9e0a8eb 100644 --- a/src/duckdb/src/include/duckdb/common/column_index_map.hpp +++ b/src/duckdb/src/include/duckdb/common/column_index_map.hpp @@ -9,7 +9,8 @@ namespace duckdb { struct ColumnIndexHashFunction { uint64_t operator()(const ColumnIndex &index) const { - auto hasher = std::hash(); + auto index_hasher = std::hash(); + auto field_hasher = std::hash(); queue> to_hash; hash_t result = 0; @@ -20,7 +21,12 @@ struct ColumnIndexHashFunction { for (auto &child : children) { to_hash.push(child); } - result ^= hasher(current.get().GetPrimaryIndex()); + + if (current.get().HasPrimaryIndex()) { + result ^= index_hasher(current.get().GetPrimaryIndex()); + } else { + result ^= field_hasher(current.get().GetFieldName()); + } to_hash.pop(); } return result; diff --git a/src/duckdb/src/include/duckdb/common/encryption_functions.hpp b/src/duckdb/src/include/duckdb/common/encryption_functions.hpp index 35a439411..3dba1e0bc 100644 --- a/src/duckdb/src/include/duckdb/common/encryption_functions.hpp +++ b/src/duckdb/src/include/duckdb/common/encryption_functions.hpp @@ -1,6 +1,15 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/common/encryption_functions.hpp +// +// +//===----------------------------------------------------------------------===// + #pragma once #include "duckdb/common/helper.hpp" +#include "duckdb/common/encryption_types.hpp" #include "duckdb/common/serializer/memory_stream.hpp" namespace duckdb { @@ -9,24 +18,6 @@ class DatabaseInstance; class AttachedDatabase; class FileBuffer; -struct EncryptionTag { - EncryptionTag(); - data_ptr_t data(); - idx_t size() const; - -private: - unique_ptr tag; -}; - -struct EncryptionNonce { - EncryptionNonce(); - data_ptr_t data(); - idx_t size() const; - -private: - unique_ptr nonce; -}; - class AdditionalAuthenticatedData { public: explicit AdditionalAuthenticatedData(Allocator &allocator) diff --git a/src/duckdb/src/include/duckdb/common/encryption_key_manager.hpp b/src/duckdb/src/include/duckdb/common/encryption_key_manager.hpp index cec709f4e..dd1970662 100644 --- a/src/duckdb/src/include/duckdb/common/encryption_key_manager.hpp +++ b/src/duckdb/src/include/duckdb/common/encryption_key_manager.hpp @@ -32,6 +32,10 @@ class EncryptionKey { return key; } + data_ptr_t GetData() { + return key; + } + public: static void LockEncryptionKey(data_ptr_t key, idx_t key_len = MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); static void UnlockEncryptionKey(data_ptr_t key, idx_t key_len = MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); @@ -50,6 +54,8 @@ class EncryptionKeyManager : public ObjectCacheEntry { void AddKey(const string &key_name, data_ptr_t key); bool HasKey(const string &key_name) const; void DeleteKey(const string &key_name); + void ClearKey(const string &key_name); + void EraseKey(const string &key_name); const_data_ptr_t GetKey(const string &key_name) const; public: diff --git a/src/duckdb/src/include/duckdb/common/encryption_state.hpp b/src/duckdb/src/include/duckdb/common/encryption_state.hpp index 4aece4a2f..4f3bfbcc9 100644 --- a/src/duckdb/src/include/duckdb/common/encryption_state.hpp +++ b/src/duckdb/src/include/duckdb/common/encryption_state.hpp @@ -8,40 +8,72 @@ #pragma once +#include "duckdb/common/encryption_types.hpp" #include "duckdb/common/helper.hpp" #include "duckdb/common/string_util.hpp" +#include "duckdb/common/random_engine.hpp" +#include "duckdb/common/serializer/memory_stream.hpp" namespace duckdb { -class EncryptionTypes { +struct EncryptionNonce; + +struct EncryptionStateMetadata { +private: + const EncryptionTypes::CipherType cipher; + const idx_t key_len; + const EncryptionTypes::EncryptionVersion version; + public: - enum CipherType : uint8_t { INVALID = 0, GCM = 1, CTR = 2, CBC = 3 }; - enum KeyDerivationFunction : uint8_t { DEFAULT = 0, SHA256 = 1, PBKDF2 = 2 }; - enum Mode { ENCRYPT, DECRYPT }; - - static string CipherToString(CipherType cipher_p); - static CipherType StringToCipher(const string &encryption_cipher_p); - static string KDFToString(KeyDerivationFunction kdf_p); - static KeyDerivationFunction StringToKDF(const string &key_derivation_function_p); + EncryptionStateMetadata() : cipher(EncryptionTypes::INVALID), key_len(0), version(EncryptionTypes::NONE) { + } + + EncryptionStateMetadata(EncryptionTypes::CipherType cipher_p, idx_t key_len_p, + EncryptionTypes::EncryptionVersion version_p) + : cipher(cipher_p), key_len(key_len_p), version(version_p) { + } + + bool IsValid() const { + if (!(cipher != EncryptionTypes::INVALID && key_len > 0)) { + throw InvalidInputException("EncryptionStateMetadata is not initialized!"); + } + return true; + } + + EncryptionTypes::CipherType GetCipher() const { + return cipher; + } + + idx_t GetKeyLen() const { + return key_len; + } + + EncryptionTypes::EncryptionVersion GetVersion() const { + return version; + } }; class EncryptionState { public: - DUCKDB_API explicit EncryptionState(EncryptionTypes::CipherType cipher_p, idx_t key_len); + DUCKDB_API explicit EncryptionState(unique_ptr metadata); DUCKDB_API virtual ~EncryptionState(); public: - DUCKDB_API virtual void InitializeEncryption(const_data_ptr_t iv, idx_t iv_len, const_data_ptr_t key, idx_t key_len, + DUCKDB_API virtual void InitializeEncryption(EncryptionNonce &nonce, const_data_ptr_t key, const_data_ptr_t aad = nullptr, idx_t aad_len = 0); - DUCKDB_API virtual void InitializeDecryption(const_data_ptr_t iv, idx_t iv_len, const_data_ptr_t key, idx_t key_len, + DUCKDB_API virtual void InitializeDecryption(EncryptionNonce &nonce, const_data_ptr_t key, const_data_ptr_t aad = nullptr, idx_t aad_len = 0); DUCKDB_API virtual size_t Process(const_data_ptr_t in, idx_t in_len, data_ptr_t out, idx_t out_len); DUCKDB_API virtual size_t Finalize(data_ptr_t out, idx_t out_len, data_ptr_t tag, idx_t tag_len); DUCKDB_API virtual void GenerateRandomData(data_ptr_t data, idx_t len); -protected: - EncryptionTypes::CipherType cipher; - idx_t key_len; +public: + unique_ptr metadata; + +public: + EncryptionTypes::CipherType GetCipher() const { + return metadata->GetCipher(); + } }; class EncryptionUtil { @@ -49,17 +81,15 @@ class EncryptionUtil { DUCKDB_API explicit EncryptionUtil() {}; public: - virtual shared_ptr CreateEncryptionState(EncryptionTypes::CipherType cipher_p, - idx_t key_len = 0) const { - return make_shared_ptr(cipher_p, key_len); + virtual shared_ptr CreateEncryptionState(unique_ptr metadata) const { + return make_shared_ptr(std::move(metadata)); } virtual ~EncryptionUtil() { } - //! Whether the EncryptionUtil supports encryption (some may only support decryption) - DUCKDB_API virtual bool SupportsEncryption() { - return true; + DUCKDB_API virtual void OverrideEncryptionUtil() { + throw InvalidInputException("Abstract Method"); } }; diff --git a/src/duckdb/src/include/duckdb/common/encryption_types.hpp b/src/duckdb/src/include/duckdb/common/encryption_types.hpp new file mode 100644 index 000000000..9680cb4b1 --- /dev/null +++ b/src/duckdb/src/include/duckdb/common/encryption_types.hpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/common/encryption_types.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/string_util.hpp" +#include "duckdb/storage/storage_info.hpp" + +namespace duckdb { + +class EncryptionTypes { +public: + enum CipherType : uint8_t { INVALID = 0, GCM = 1, CTR = 2, CBC = 3 }; + enum KeyDerivationFunction : uint8_t { DEFAULT = 0, SHA256 = 1, PBKDF2 = 2 }; + enum Mode { ENCRYPT, DECRYPT }; + enum EncryptionVersion : uint8_t { V0_0 = 0, V0_1 = 1, NONE = 127 }; + + static string CipherToString(CipherType cipher_p); + static CipherType StringToCipher(const string &encryption_cipher_p); + static string KDFToString(KeyDerivationFunction kdf_p); + static KeyDerivationFunction StringToKDF(const string &key_derivation_function_p); + static EncryptionVersion StringToVersion(const string &encryption_version_p); +}; + +struct EncryptionTag { + EncryptionTag(); + data_ptr_t data(); + idx_t size() const; + bool IsAllZeros() const; + void SetSize(idx_t size); + +private: + unique_ptr tag; + idx_t tag_len; +}; + +struct EncryptionCanary { + EncryptionCanary(); + data_ptr_t data(); + idx_t size() const; + +private: + unique_ptr canary; +}; + +struct EncryptionNonce { + explicit EncryptionNonce(EncryptionTypes::CipherType cipher = EncryptionTypes::GCM, + EncryptionTypes::EncryptionVersion version = EncryptionTypes::EncryptionVersion::V0_1); + data_ptr_t data(); + idx_t size() const; + idx_t total_size() const; + idx_t size_deprecated() const; + + void SetSize(idx_t length); + +private: + unique_ptr nonce; + idx_t nonce_len; + +private: + EncryptionTypes::EncryptionVersion version; + EncryptionTypes::CipherType cipher; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enum_util.hpp b/src/duckdb/src/include/duckdb/common/enum_util.hpp index d1b35028c..d614fe308 100644 --- a/src/duckdb/src/include/duckdb/common/enum_util.hpp +++ b/src/duckdb/src/include/duckdb/common/enum_util.hpp @@ -38,6 +38,8 @@ enum class ARTHandlingResult : uint8_t; enum class ARTScanHandling : uint8_t; +enum class ARTScanResult : uint8_t; + enum class AccessMode : uint8_t; enum class AggregateCombineType : uint8_t; @@ -50,6 +52,8 @@ enum class AggregateOrderDependent : uint8_t; enum class AggregateType : uint8_t; +enum class AllowParserOverride : uint8_t; + enum class AlterDatabaseType : uint8_t; enum class AlterForeignKeyType : uint8_t; @@ -158,6 +162,8 @@ enum class DependencyEntryType : uint8_t; enum class DeprecatedIndexType : uint8_t; +enum class DeprecatedUsingKeySyntax : uint8_t; + enum class DestroyBufferUpon : uint8_t; enum class DistinctType : uint8_t; @@ -190,6 +196,8 @@ enum class ExtensionUpdateResultTag : uint8_t; enum class ExtraDropInfoType : uint8_t; +enum class ExtraPersistentColumnDataType : uint8_t; + enum class ExtraTypeInfoType : uint8_t; enum class FileBufferType : uint8_t; @@ -302,8 +310,12 @@ enum class OperatorResultType : uint8_t; enum class OptimizerType : uint32_t; +enum class OrderByColumnType : uint8_t; + enum class OrderByNullType : uint8_t; +enum class OrderByStatistics : uint8_t; + enum class OrderPreservationType : uint8_t; enum class OrderType : uint8_t; @@ -498,6 +510,9 @@ const char* EnumUtil::ToChars(ARTHandlingResult value); template<> const char* EnumUtil::ToChars(ARTScanHandling value); +template<> +const char* EnumUtil::ToChars(ARTScanResult value); + template<> const char* EnumUtil::ToChars(AccessMode value); @@ -516,6 +531,9 @@ const char* EnumUtil::ToChars(AggregateOrderDependent v template<> const char* EnumUtil::ToChars(AggregateType value); +template<> +const char* EnumUtil::ToChars(AllowParserOverride value); + template<> const char* EnumUtil::ToChars(AlterDatabaseType value); @@ -678,6 +696,9 @@ const char* EnumUtil::ToChars(DependencyEntryType value); template<> const char* EnumUtil::ToChars(DeprecatedIndexType value); +template<> +const char* EnumUtil::ToChars(DeprecatedUsingKeySyntax value); + template<> const char* EnumUtil::ToChars(DestroyBufferUpon value); @@ -726,6 +747,9 @@ const char* EnumUtil::ToChars(ExtensionUpdateResultTag template<> const char* EnumUtil::ToChars(ExtraDropInfoType value); +template<> +const char* EnumUtil::ToChars(ExtraPersistentColumnDataType value); + template<> const char* EnumUtil::ToChars(ExtraTypeInfoType value); @@ -894,9 +918,15 @@ const char* EnumUtil::ToChars(OperatorResultType value); template<> const char* EnumUtil::ToChars(OptimizerType value); +template<> +const char* EnumUtil::ToChars(OrderByColumnType value); + template<> const char* EnumUtil::ToChars(OrderByNullType value); +template<> +const char* EnumUtil::ToChars(OrderByStatistics value); + template<> const char* EnumUtil::ToChars(OrderPreservationType value); @@ -1183,6 +1213,9 @@ ARTHandlingResult EnumUtil::FromString(const char *value); template<> ARTScanHandling EnumUtil::FromString(const char *value); +template<> +ARTScanResult EnumUtil::FromString(const char *value); + template<> AccessMode EnumUtil::FromString(const char *value); @@ -1201,6 +1234,9 @@ AggregateOrderDependent EnumUtil::FromString(const char template<> AggregateType EnumUtil::FromString(const char *value); +template<> +AllowParserOverride EnumUtil::FromString(const char *value); + template<> AlterDatabaseType EnumUtil::FromString(const char *value); @@ -1363,6 +1399,9 @@ DependencyEntryType EnumUtil::FromString(const char *value) template<> DeprecatedIndexType EnumUtil::FromString(const char *value); +template<> +DeprecatedUsingKeySyntax EnumUtil::FromString(const char *value); + template<> DestroyBufferUpon EnumUtil::FromString(const char *value); @@ -1411,6 +1450,9 @@ ExtensionUpdateResultTag EnumUtil::FromString(const ch template<> ExtraDropInfoType EnumUtil::FromString(const char *value); +template<> +ExtraPersistentColumnDataType EnumUtil::FromString(const char *value); + template<> ExtraTypeInfoType EnumUtil::FromString(const char *value); @@ -1579,9 +1621,15 @@ OperatorResultType EnumUtil::FromString(const char *value); template<> OptimizerType EnumUtil::FromString(const char *value); +template<> +OrderByColumnType EnumUtil::FromString(const char *value); + template<> OrderByNullType EnumUtil::FromString(const char *value); +template<> +OrderByStatistics EnumUtil::FromString(const char *value); + template<> OrderPreservationType EnumUtil::FromString(const char *value); diff --git a/src/duckdb/src/include/duckdb/common/enums/allow_parser_override.hpp b/src/duckdb/src/include/duckdb/common/enums/allow_parser_override.hpp new file mode 100644 index 000000000..f342cf224 --- /dev/null +++ b/src/duckdb/src/include/duckdb/common/enums/allow_parser_override.hpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/common/enums/allow_parser_override.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/constants.hpp" + +namespace duckdb { + +enum class AllowParserOverride : uint8_t { + DEFAULT_OVERRIDE, + FALLBACK_OVERRIDE, + STRICT_OVERRIDE, + STRICT_WHEN_SUPPORTED +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enums/catalog_type.hpp b/src/duckdb/src/include/duckdb/common/enums/catalog_type.hpp index 3e18e666e..e5381d1ab 100644 --- a/src/duckdb/src/include/duckdb/common/enums/catalog_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/catalog_type.hpp @@ -26,6 +26,7 @@ enum class CatalogType : uint8_t { COLLATION_ENTRY = 7, TYPE_ENTRY = 8, DATABASE_ENTRY = 9, + COORDINATE_SYSTEM_ENTRY = 10, // functions TABLE_FUNCTION_ENTRY = 25, diff --git a/src/duckdb/src/include/duckdb/common/enums/compression_type.hpp b/src/duckdb/src/include/duckdb/common/enums/compression_type.hpp index 5198f7627..988667145 100644 --- a/src/duckdb/src/include/duckdb/common/enums/compression_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/compression_type.hpp @@ -79,7 +79,6 @@ struct CompressionAvailabilityResult { CompressionAvailabilityResult CompressionTypeIsAvailable(CompressionType compression_type, optional_ptr storage_manager = nullptr); vector ListCompressionTypes(void); -CompressionType CompressionTypeFromString(const string &str); string CompressionTypeToString(CompressionType type); } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enums/deprecated_using_key_syntax.hpp b/src/duckdb/src/include/duckdb/common/enums/deprecated_using_key_syntax.hpp new file mode 100644 index 000000000..3d2bf402f --- /dev/null +++ b/src/duckdb/src/include/duckdb/common/enums/deprecated_using_key_syntax.hpp @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/common/enums/deprecated_using_key_syntax.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/constants.hpp" + +namespace duckdb { + +enum class DeprecatedUsingKeySyntax : uint8_t { DEFAULT = 0, UNION_AS_UNION_ALL = 1 }; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enums/expression_type.hpp b/src/duckdb/src/include/duckdb/common/enums/expression_type.hpp index 0a5728aa6..8a6f38eae 100644 --- a/src/duckdb/src/include/duckdb/common/enums/expression_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/expression_type.hpp @@ -138,6 +138,7 @@ enum class ExpressionType : uint8_t { FUNCTION_REF = 204, TABLE_REF = 205, LAMBDA_REF = 206, + TYPE = 207, // ----------------------------- // Miscellaneous @@ -180,6 +181,7 @@ enum class ExpressionClass : uint8_t { POSITIONAL_REFERENCE = 18, BETWEEN = 19, LAMBDA_REF = 20, + TYPE = 21, //===--------------------------------------------------------------------===// // Bound Expressions //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/common/enums/lambda_syntax.hpp b/src/duckdb/src/include/duckdb/common/enums/lambda_syntax.hpp new file mode 100644 index 000000000..c729b953e --- /dev/null +++ b/src/duckdb/src/include/duckdb/common/enums/lambda_syntax.hpp @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/common/enums/lambda_syntax.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/constants.hpp" + +namespace duckdb { + +enum class LambdaSyntax : uint8_t { DEFAULT = 0, ENABLE_SINGLE_ARROW = 1, DISABLE_SINGLE_ARROW = 2 }; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp b/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp index 55dc0b62e..775f8e702 100644 --- a/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp @@ -27,9 +27,12 @@ enum class MemoryTag : uint8_t { EXTENSION = 11, TRANSACTION = 12, EXTERNAL_FILE_CACHE = 13, - WINDOW = 14 + WINDOW = 14, + OBJECT_CACHE = 15, + // Intentionally left as the end, used to indicate memory tag type count. + UNKNOWN = 16, }; -static constexpr const idx_t MEMORY_TAG_COUNT = 15; +static constexpr const idx_t MEMORY_TAG_COUNT = static_cast(MemoryTag::UNKNOWN); } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp b/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp index 60db5da1f..53d860deb 100644 --- a/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp @@ -31,78 +31,78 @@ enum class MetricGroup : uint8_t { enum class MetricType : uint8_t { // Core metrics - CPU_TIME, - CUMULATIVE_CARDINALITY, - CUMULATIVE_ROWS_SCANNED, - EXTRA_INFO, - LATENCY, - QUERY_NAME, - RESULT_SET_SIZE, - ROWS_RETURNED, + CPU_TIME = 2, + CUMULATIVE_CARDINALITY = 4, + CUMULATIVE_ROWS_SCANNED = 7, + EXTRA_INFO = 3, + LATENCY = 11, + QUERY_NAME = 0, + RESULT_SET_SIZE = 10, + ROWS_RETURNED = 12, // Execution metrics - BLOCKED_THREAD_TIME, - SYSTEM_PEAK_BUFFER_MEMORY, - SYSTEM_PEAK_TEMP_DIR_SIZE, - TOTAL_MEMORY_ALLOCATED, + BLOCKED_THREAD_TIME = 1, + SYSTEM_PEAK_BUFFER_MEMORY = 14, + SYSTEM_PEAK_TEMP_DIR_SIZE = 15, + TOTAL_MEMORY_ALLOCATED = 91, // File metrics - ATTACH_LOAD_STORAGE_LATENCY, - ATTACH_REPLAY_WAL_LATENCY, - CHECKPOINT_LATENCY, - COMMIT_LOCAL_STORAGE_LATENCY, - TOTAL_BYTES_READ, - TOTAL_BYTES_WRITTEN, - WAITING_TO_ATTACH_LATENCY, - WAL_REPLAY_ENTRY_COUNT, - WRITE_TO_WAL_LATENCY, + ATTACH_LOAD_STORAGE_LATENCY = 92, + ATTACH_REPLAY_WAL_LATENCY = 93, + CHECKPOINT_LATENCY = 94, + COMMIT_LOCAL_STORAGE_LATENCY = 95, + TOTAL_BYTES_READ = 16, + TOTAL_BYTES_WRITTEN = 17, + WAITING_TO_ATTACH_LATENCY = 96, + WAL_REPLAY_ENTRY_COUNT = 97, + WRITE_TO_WAL_LATENCY = 98, // Operator metrics - OPERATOR_CARDINALITY, - OPERATOR_NAME, - OPERATOR_ROWS_SCANNED, - OPERATOR_TIMING, - OPERATOR_TYPE, + OPERATOR_CARDINALITY = 6, + OPERATOR_NAME = 13, + OPERATOR_ROWS_SCANNED = 8, + OPERATOR_TIMING = 9, + OPERATOR_TYPE = 5, // Optimizer metrics - OPTIMIZER_EXPRESSION_REWRITER, - OPTIMIZER_FILTER_PULLUP, - OPTIMIZER_FILTER_PUSHDOWN, - OPTIMIZER_EMPTY_RESULT_PULLUP, - OPTIMIZER_CTE_FILTER_PUSHER, - OPTIMIZER_REGEX_RANGE, - OPTIMIZER_IN_CLAUSE, - OPTIMIZER_JOIN_ORDER, - OPTIMIZER_DELIMINATOR, - OPTIMIZER_UNNEST_REWRITER, - OPTIMIZER_UNUSED_COLUMNS, - OPTIMIZER_STATISTICS_PROPAGATION, - OPTIMIZER_COMMON_SUBEXPRESSIONS, - OPTIMIZER_COMMON_AGGREGATE, - OPTIMIZER_COLUMN_LIFETIME, - OPTIMIZER_BUILD_SIDE_PROBE_SIDE, - OPTIMIZER_LIMIT_PUSHDOWN, - OPTIMIZER_ROW_GROUP_PRUNER, - OPTIMIZER_TOP_N, - OPTIMIZER_TOP_N_WINDOW_ELIMINATION, - OPTIMIZER_COMPRESSED_MATERIALIZATION, - OPTIMIZER_DUPLICATE_GROUPS, - OPTIMIZER_REORDER_FILTER, - OPTIMIZER_SAMPLING_PUSHDOWN, - OPTIMIZER_JOIN_FILTER_PUSHDOWN, - OPTIMIZER_EXTENSION, - OPTIMIZER_MATERIALIZED_CTE, - OPTIMIZER_SUM_REWRITER, - OPTIMIZER_LATE_MATERIALIZATION, - OPTIMIZER_CTE_INLINING, - OPTIMIZER_COMMON_SUBPLAN, - OPTIMIZER_JOIN_ELIMINATION, - OPTIMIZER_WINDOW_SELF_JOIN, + OPTIMIZER_EXPRESSION_REWRITER = 26, + OPTIMIZER_FILTER_PULLUP = 27, + OPTIMIZER_FILTER_PUSHDOWN = 28, + OPTIMIZER_EMPTY_RESULT_PULLUP = 29, + OPTIMIZER_CTE_FILTER_PUSHER = 30, + OPTIMIZER_REGEX_RANGE = 31, + OPTIMIZER_IN_CLAUSE = 32, + OPTIMIZER_JOIN_ORDER = 33, + OPTIMIZER_DELIMINATOR = 34, + OPTIMIZER_UNNEST_REWRITER = 35, + OPTIMIZER_UNUSED_COLUMNS = 36, + OPTIMIZER_STATISTICS_PROPAGATION = 37, + OPTIMIZER_COMMON_SUBEXPRESSIONS = 38, + OPTIMIZER_COMMON_AGGREGATE = 39, + OPTIMIZER_COLUMN_LIFETIME = 40, + OPTIMIZER_BUILD_SIDE_PROBE_SIDE = 41, + OPTIMIZER_LIMIT_PUSHDOWN = 42, + OPTIMIZER_TOP_N = 43, + OPTIMIZER_COMPRESSED_MATERIALIZATION = 44, + OPTIMIZER_DUPLICATE_GROUPS = 45, + OPTIMIZER_REORDER_FILTER = 46, + OPTIMIZER_SAMPLING_PUSHDOWN = 47, + OPTIMIZER_JOIN_FILTER_PUSHDOWN = 48, + OPTIMIZER_EXTENSION = 49, + OPTIMIZER_MATERIALIZED_CTE = 50, + OPTIMIZER_SUM_REWRITER = 51, + OPTIMIZER_LATE_MATERIALIZATION = 52, + OPTIMIZER_CTE_INLINING = 53, + OPTIMIZER_ROW_GROUP_PRUNER = 54, + OPTIMIZER_TOP_N_WINDOW_ELIMINATION = 55, + OPTIMIZER_COMMON_SUBPLAN = 56, + OPTIMIZER_JOIN_ELIMINATION = 57, + OPTIMIZER_WINDOW_SELF_JOIN = 58, // PhaseTiming metrics - ALL_OPTIMIZERS, - CUMULATIVE_OPTIMIZER_TIMING, - PHYSICAL_PLANNER, - PHYSICAL_PLANNER_COLUMN_BINDING, - PHYSICAL_PLANNER_CREATE_PLAN, - PHYSICAL_PLANNER_RESOLVE_TYPES, - PLANNER, - PLANNER_BINDING, + ALL_OPTIMIZERS = 18, + CUMULATIVE_OPTIMIZER_TIMING = 19, + PHYSICAL_PLANNER = 22, + PHYSICAL_PLANNER_COLUMN_BINDING = 23, + PHYSICAL_PLANNER_CREATE_PLAN = 25, + PHYSICAL_PLANNER_RESOLVE_TYPES = 24, + PLANNER = 20, + PLANNER_BINDING = 21, }; struct MetricTypeHashFunction { @@ -116,24 +116,9 @@ typedef unordered_map profiler_metric class MetricsUtils { public: - static constexpr uint8_t START_CORE = static_cast(MetricType::CPU_TIME); - static constexpr uint8_t END_CORE = static_cast(MetricType::ROWS_RETURNED); - - static constexpr uint8_t START_EXECUTION = static_cast(MetricType::BLOCKED_THREAD_TIME); - static constexpr uint8_t END_EXECUTION = static_cast(MetricType::TOTAL_MEMORY_ALLOCATED); - - static constexpr uint8_t START_FILE = static_cast(MetricType::ATTACH_LOAD_STORAGE_LATENCY); - static constexpr uint8_t END_FILE = static_cast(MetricType::WRITE_TO_WAL_LATENCY); - - static constexpr uint8_t START_OPERATOR = static_cast(MetricType::OPERATOR_CARDINALITY); - static constexpr uint8_t END_OPERATOR = static_cast(MetricType::OPERATOR_TYPE); - static constexpr uint8_t START_OPTIMIZER = static_cast(MetricType::OPTIMIZER_EXPRESSION_REWRITER); static constexpr uint8_t END_OPTIMIZER = static_cast(MetricType::OPTIMIZER_WINDOW_SELF_JOIN); - static constexpr uint8_t START_PHASE_TIMING = static_cast(MetricType::ALL_OPTIMIZERS); - static constexpr uint8_t END_PHASE_TIMING = static_cast(MetricType::PLANNER_BINDING); - public: // All metrics diff --git a/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp b/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp index 7207dc873..996435114 100644 --- a/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp @@ -15,39 +15,39 @@ namespace duckdb { enum class OptimizerType : uint32_t { INVALID = 0, - EXPRESSION_REWRITER, - FILTER_PULLUP, - FILTER_PUSHDOWN, - EMPTY_RESULT_PULLUP, - CTE_FILTER_PUSHER, - REGEX_RANGE, - IN_CLAUSE, - JOIN_ORDER, - DELIMINATOR, - UNNEST_REWRITER, - UNUSED_COLUMNS, - STATISTICS_PROPAGATION, - COMMON_SUBEXPRESSIONS, - COMMON_AGGREGATE, - COLUMN_LIFETIME, - BUILD_SIDE_PROBE_SIDE, - LIMIT_PUSHDOWN, - ROW_GROUP_PRUNER, - TOP_N, - TOP_N_WINDOW_ELIMINATION, - COMPRESSED_MATERIALIZATION, - DUPLICATE_GROUPS, - REORDER_FILTER, - SAMPLING_PUSHDOWN, - JOIN_FILTER_PUSHDOWN, - EXTENSION, - MATERIALIZED_CTE, - SUM_REWRITER, - LATE_MATERIALIZATION, - CTE_INLINING, - COMMON_SUBPLAN, - JOIN_ELIMINATION, - WINDOW_SELF_JOIN + EXPRESSION_REWRITER = 1, + FILTER_PULLUP = 2, + FILTER_PUSHDOWN = 3, + EMPTY_RESULT_PULLUP = 4, + CTE_FILTER_PUSHER = 5, + REGEX_RANGE = 6, + IN_CLAUSE = 7, + JOIN_ORDER = 8, + DELIMINATOR = 9, + UNNEST_REWRITER = 10, + UNUSED_COLUMNS = 11, + STATISTICS_PROPAGATION = 12, + COMMON_SUBEXPRESSIONS = 13, + COMMON_AGGREGATE = 14, + COLUMN_LIFETIME = 15, + BUILD_SIDE_PROBE_SIDE = 16, + LIMIT_PUSHDOWN = 17, + TOP_N = 18, + COMPRESSED_MATERIALIZATION = 19, + DUPLICATE_GROUPS = 20, + REORDER_FILTER = 21, + SAMPLING_PUSHDOWN = 22, + JOIN_FILTER_PUSHDOWN = 23, + EXTENSION = 24, + MATERIALIZED_CTE = 25, + SUM_REWRITER = 26, + LATE_MATERIALIZATION = 27, + CTE_INLINING = 28, + ROW_GROUP_PRUNER = 29, + TOP_N_WINDOW_ELIMINATION = 30, + COMMON_SUBPLAN = 31, + JOIN_ELIMINATION = 32, + WINDOW_SELF_JOIN = 33 }; string OptimizerTypeToString(OptimizerType type); diff --git a/src/duckdb/src/include/duckdb/common/exception.hpp b/src/duckdb/src/include/duckdb/common/exception.hpp index 17d430201..7a6e5549a 100644 --- a/src/duckdb/src/include/duckdb/common/exception.hpp +++ b/src/duckdb/src/include/duckdb/common/exception.hpp @@ -301,6 +301,7 @@ class SequenceException : public Exception { class InterruptException : public Exception { public: + static constexpr const char *INTERRUPT_MESSAGE = "Interrupted!"; DUCKDB_API InterruptException(); }; diff --git a/src/duckdb/src/include/duckdb/common/extra_type_info.hpp b/src/duckdb/src/include/duckdb/common/extra_type_info.hpp index 152e37d15..6fe9e1d00 100644 --- a/src/duckdb/src/include/duckdb/common/extra_type_info.hpp +++ b/src/duckdb/src/include/duckdb/common/extra_type_info.hpp @@ -15,6 +15,8 @@ namespace duckdb { +class ParsedExpression; + //! Extra Type Info Type enum class ExtraTypeInfoType : uint8_t { INVALID_TYPE_INFO = 0, @@ -24,13 +26,13 @@ enum class ExtraTypeInfoType : uint8_t { LIST_TYPE_INFO = 4, STRUCT_TYPE_INFO = 5, ENUM_TYPE_INFO = 6, - USER_TYPE_INFO = 7, + UNBOUND_TYPE_INFO = 7, AGGREGATE_STATE_TYPE_INFO = 8, ARRAY_TYPE_INFO = 9, ANY_TYPE_INFO = 10, INTEGER_LITERAL_TYPE_INFO = 11, TEMPLATE_TYPE_INFO = 12, - GEO_TYPE_INFO = 13 + GEO_TYPE_INFO = 13, }; struct ExtraTypeInfo { @@ -158,28 +160,6 @@ struct AggregateStateTypeInfo : public ExtraTypeInfo { AggregateStateTypeInfo(); }; -struct UserTypeInfo : public ExtraTypeInfo { - explicit UserTypeInfo(string name_p); - UserTypeInfo(string name_p, vector modifiers_p); - UserTypeInfo(string catalog_p, string schema_p, string name_p, vector modifiers_p); - - string catalog; - string schema; - string user_type_name; - vector user_type_modifiers; - -public: - void Serialize(Serializer &serializer) const override; - static shared_ptr Deserialize(Deserializer &source); - shared_ptr Copy() const override; - -protected: - bool EqualsInternal(ExtraTypeInfo *other_p) const override; - -private: - UserTypeInfo(); -}; - // If this type is primarily stored in the catalog or not. Enums from Pandas/Factors are not in the catalog. enum EnumDictType : uint8_t { INVALID = 0, VECTOR_DICT = 1 }; @@ -294,4 +274,20 @@ struct GeoTypeInfo : public ExtraTypeInfo { bool EqualsInternal(ExtraTypeInfo *other_p) const override; }; +struct UnboundTypeInfo : public ExtraTypeInfo { + explicit UnboundTypeInfo(unique_ptr expr_p); + + unique_ptr expr; + + void Serialize(Serializer &serializer) const override; + static shared_ptr Deserialize(Deserializer &source); + shared_ptr Copy() const override; + +protected: + bool EqualsInternal(ExtraTypeInfo *other_p) const override; + +private: + UnboundTypeInfo(); +}; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/file_buffer.hpp b/src/duckdb/src/include/duckdb/common/file_buffer.hpp index e0fcfcdec..0a9dfe695 100644 --- a/src/duckdb/src/include/duckdb/common/file_buffer.hpp +++ b/src/duckdb/src/include/duckdb/common/file_buffer.hpp @@ -57,7 +57,7 @@ class FileBuffer { // Same rules as the constructor. We add room for a header, in addition to // the requested user bytes. We then sector-align the result. - void Resize(uint64_t user_size, BlockManager &block_manager); + void Resize(uint64_t user_size, idx_t block_header_size); void Resize(BlockManager &block_manager); idx_t GetHeaderSize() const { diff --git a/src/duckdb/src/include/duckdb/common/file_open_flags.hpp b/src/duckdb/src/include/duckdb/common/file_open_flags.hpp index 89cd24b78..9f71e2c54 100644 --- a/src/duckdb/src/include/duckdb/common/file_open_flags.hpp +++ b/src/duckdb/src/include/duckdb/common/file_open_flags.hpp @@ -31,6 +31,7 @@ class FileOpenFlags { static constexpr idx_t FILE_FLAGS_NULL_IF_EXISTS = idx_t(1 << 10); static constexpr idx_t FILE_FLAGS_MULTI_CLIENT_ACCESS = idx_t(1 << 11); static constexpr idx_t FILE_FLAGS_DISABLE_LOGGING = idx_t(1 << 12); + static constexpr idx_t FILE_FLAGS_ENABLE_EXTENSION_INSTALL = idx_t(1 << 13); public: FileOpenFlags() = default; @@ -128,6 +129,9 @@ class FileOpenFlags { inline bool DisableLogging() const { return flags & FILE_FLAGS_DISABLE_LOGGING; } + inline bool EnableExtensionInstall() const { + return flags & FILE_FLAGS_ENABLE_EXTENSION_INSTALL; + } inline idx_t GetFlagsInternal() const { return flags; } @@ -173,6 +177,9 @@ class FileFlags { //! Disables logging to avoid infinite loops when using FileHandle-backed log storage static constexpr FileOpenFlags FILE_FLAGS_DISABLE_LOGGING = FileOpenFlags(FileOpenFlags::FILE_FLAGS_DISABLE_LOGGING); + //! Opened file is allowed to be a duckdb_extension + static constexpr FileOpenFlags FILE_FLAGS_ENABLE_EXTENSION_INSTALL = + FileOpenFlags(FileOpenFlags::FILE_FLAGS_ENABLE_EXTENSION_INSTALL); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/file_system.hpp b/src/duckdb/src/include/duckdb/common/file_system.hpp index 825f22d17..b5a04edca 100644 --- a/src/duckdb/src/include/duckdb/common/file_system.hpp +++ b/src/duckdb/src/include/duckdb/common/file_system.hpp @@ -38,6 +38,7 @@ class FileSystem; class Logger; class ClientContext; class QueryContext; +class MultiFileList; enum class FileType { //! Regular file @@ -228,13 +229,15 @@ class FileSystem { DUCKDB_API static optional_idx GetAvailableDiskSpace(const string &path); //! Path separator for path DUCKDB_API virtual string PathSeparator(const string &path); - //! Checks if path is starts with separator (i.e., '/' on UNIX '\\' on Windows) - DUCKDB_API bool IsPathAbsolute(const string &path); - //! Normalize an absolute path - the goal of normalizing is converting "\test.db" and "C:/test.db" into "C:\test.db" - //! so that the database system cache can correctly - DUCKDB_API string NormalizeAbsolutePath(const string &path); + //! Checks if path is is an absolute path + DUCKDB_API virtual bool IsPathAbsolute(const string &path); //! Join two paths together DUCKDB_API string JoinPath(const string &a, const string &path); + // Join N paths together + template + string JoinPath(const string &a, const string &b, ARGS... args) { + return JoinPath(JoinPath(a, b), args...); + } //! Convert separators in a path to the local separators (e.g. convert "/" into \\ on windows) DUCKDB_API string ConvertSeparators(const string &path); //! Extract the base name of a file (e.g. if the input is lib/example.dll the base name is 'example') @@ -251,7 +254,11 @@ class FileSystem { DUCKDB_API static bool HasGlob(const string &str); //! Runs a glob on the file system, returning a list of matching files DUCKDB_API virtual vector Glob(const string &path, FileOpener *opener = nullptr); - DUCKDB_API vector GlobFiles(const string &path, ClientContext &context, + DUCKDB_API unique_ptr Glob(const string &path, const FileGlobInput &input, + optional_ptr opener); + DUCKDB_API unique_ptr GlobFileList(const string &path, + const FileGlobInput &input = FileGlobOptions::DISALLOW_EMPTY); + DUCKDB_API vector GlobFiles(const string &pattern, const FileGlobInput &input = FileGlobOptions::DISALLOW_EMPTY); //! registers a sub-file system to handle certain file name prefixes, e.g. http:// etc. @@ -305,6 +312,9 @@ class FileSystem { DUCKDB_API static bool IsDirectory(const OpenFileInfo &info); + //! Canonicalize a path + DUCKDB_API virtual string CanonicalizePath(const string &path, optional_ptr opener = nullptr); + protected: DUCKDB_API virtual unique_ptr OpenFileExtended(const OpenFileInfo &path, FileOpenFlags flags, optional_ptr opener); @@ -315,6 +325,10 @@ class FileSystem { optional_ptr opener); DUCKDB_API virtual bool SupportsListFilesExtended() const; + DUCKDB_API virtual unique_ptr GlobFilesExtended(const string &path, const FileGlobInput &input, + optional_ptr opener = nullptr); + DUCKDB_API virtual bool SupportsGlobExtended() const; + public: template TARGET &Cast() { diff --git a/src/duckdb/src/include/duckdb/common/http_util.hpp b/src/duckdb/src/include/duckdb/common/http_util.hpp index a493647b3..fe17ad479 100644 --- a/src/duckdb/src/include/duckdb/common/http_util.hpp +++ b/src/duckdb/src/include/duckdb/common/http_util.hpp @@ -41,6 +41,8 @@ struct HTTPParams { float retry_backoff = DEFAULT_RETRY_BACKOFF; bool keep_alive = DEFAULT_KEEP_ALIVE; bool follow_location = true; + bool override_verify_ssl = false; + bool verify_ssl = true; string http_proxy; idx_t http_proxy_port; @@ -219,6 +221,8 @@ struct PostRequestInfo : public BaseRequest { const_data_ptr_t buffer_in; idx_t buffer_in_len; string buffer_out; + //! Used to send a GET request with a body (non-standard but supported by some servers) + bool send_post_as_get_request = false; }; class HTTPClient { @@ -231,6 +235,7 @@ class HTTPClient { virtual unique_ptr Head(HeadRequestInfo &info) = 0; virtual unique_ptr Delete(DeleteRequestInfo &info) = 0; virtual unique_ptr Post(PostRequestInfo &info) = 0; + virtual void Cleanup() {}; unique_ptr Request(BaseRequest &request); }; @@ -261,6 +266,8 @@ class HTTPUtil { static void DecomposeURL(const string &url, string &path_out, string &proto_host_port_out); static HTTPStatusCode ToStatusCode(int32_t status_code); static string GetStatusMessage(HTTPStatusCode status); + static bool IsHTTPProtocol(const string &url); + static void BumpToSecureProtocol(string &url); public: static duckdb::unique_ptr diff --git a/src/duckdb/src/include/duckdb/common/local_file_system.hpp b/src/duckdb/src/include/duckdb/common/local_file_system.hpp index 8d941475e..bdbe6c4cb 100644 --- a/src/duckdb/src/include/duckdb/common/local_file_system.hpp +++ b/src/duckdb/src/include/duckdb/common/local_file_system.hpp @@ -67,8 +67,10 @@ class LocalFileSystem : public FileSystem { //! 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 Glob(const string &path, FileOpener *opener = nullptr) override; + //! Checks if path is is an absolute path + bool IsPathAbsolute(const string &path) override; + string MakePathAbsolute(const string &input, optional_ptr opener); + bool PathStartsWithDrive(const string &path); bool CanHandleFile(const string &fpath) override { //! Whether or not a sub-system can handle a specific file path @@ -97,8 +99,9 @@ class LocalFileSystem : public FileSystem { //! Checks a file is private (checks for 600 on linux/macos, TODO: currently always returns true on windows) static bool IsPrivateFile(const string &path_p, FileOpener *opener); - // returns a C-string of the path that trims any file:/ prefix - static const char *NormalizeLocalPath(const string &path); + vector FetchFileWithoutGlob(const string &path, optional_ptr opener, bool absolute_path); + + string CanonicalizePath(const string &path_p, optional_ptr opener) override; protected: bool ListFilesExtended(const string &directory, const std::function &callback, @@ -108,12 +111,18 @@ class LocalFileSystem : public FileSystem { return true; } + unique_ptr GlobFilesExtended(const string &path, const FileGlobInput &input, + optional_ptr opener) override; + bool SupportsGlobExtended() const override { + return true; + } + + bool TryCanonicalizeExistingPath(string &path_p); + 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); - - vector FetchFileWithoutGlob(const string &path, FileOpener *opener, bool absolute_path); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/lru_cache.hpp b/src/duckdb/src/include/duckdb/common/lru_cache.hpp index 322f5d550..8fdca548f 100644 --- a/src/duckdb/src/include/duckdb/common/lru_cache.hpp +++ b/src/duckdb/src/include/duckdb/common/lru_cache.hpp @@ -11,17 +11,26 @@ #include #include "duckdb/common/common.hpp" +#include "duckdb/common/exception.hpp" #include "duckdb/common/list.hpp" #include "duckdb/common/mutex.hpp" #include "duckdb/common/shared_ptr.hpp" #include "duckdb/common/string.hpp" #include "duckdb/common/unordered_map.hpp" +#include "duckdb/storage/buffer/buffer_pool_reservation.hpp" namespace duckdb { +struct DefaultPayload { + idx_t GetWeight() const { + return 1; + } +}; + // A LRU cache implementation, whose value could be accessed in a shared manner with shared pointer. // Notice, it's not thread-safe. -template , typename KeyEqual = std::equal_to> +template , + typename KeyEqual = std::equal_to> class SharedLruCache { public: using key_type = Key; @@ -29,8 +38,8 @@ class SharedLruCache { using hasher = KeyHash; using key_equal = KeyEqual; - // @param max_memory_p: Maximum total memory (in bytes) of entries. 0 means unlimited. - explicit SharedLruCache(idx_t max_memory_p) : max_memory(max_memory_p), current_memory(0) { + // @param max_total_weight_p: Maximum total weight (in relevant unit) of entries. 0 means unlimited. + explicit SharedLruCache(idx_t max_total_weight_p) : max_total_weight(max_total_weight_p), current_total_weight(0) { } // Disable copy and move @@ -40,27 +49,32 @@ class SharedLruCache { ~SharedLruCache() = default; // Insert `value` with key `key` and explicit memory size. This will replace any previous entry with the same key. - void Put(Key key, shared_ptr value, idx_t memory_size) { + template + void Put(Key key, shared_ptr value, Types... constructor_args) { // Remove existing entry if present auto existing_it = entry_map.find(key); if (existing_it != entry_map.end()) { DeleteImpl(existing_it); } + auto payload = make_uniq(std::forward(constructor_args)...); + auto payload_weight = payload->GetWeight(); + // Evict entries if needed to make room - if (max_memory > 0 && memory_size > 0) { - EvictIfNeeded(memory_size); + if (max_total_weight > 0 && payload_weight > 0) { + EvictIfNeeded(payload_weight); } // Add new entry lru_list.emplace_front(key); Entry new_entry; new_entry.value = std::move(value); - new_entry.memory = memory_size; new_entry.lru_iterator = lru_list.begin(); + new_entry.payload = std::move(payload); + new_entry.payload_weight = payload_weight; entry_map[std::move(key)] = std::move(new_entry); - current_memory += memory_size; + current_total_weight += payload_weight; } // Delete the entry with key `key`. @@ -90,41 +104,62 @@ class SharedLruCache { void Clear() { entry_map.clear(); lru_list.clear(); - current_memory = 0; + current_total_weight = 0; + } + + // Evict entries based on their access, until we've freed at least the target number of bytes or there's no entries + // in the cache. Return number of bytes freed. + idx_t EvictToReduceAtLeast(idx_t target_weight) { + idx_t freed = 0; + while (!lru_list.empty() && freed < target_weight) { + const auto &stale_key = lru_list.back(); + auto stale_it = entry_map.find(stale_key); + D_ASSERT(stale_it != entry_map.end()); + freed += stale_it->second.payload_weight; + DeleteImpl(stale_it); + } + return freed; } - idx_t MaxMemory() const { - return max_memory; + idx_t Capacity() const { + return max_total_weight; } - idx_t CurrentMemory() const { - return current_memory; + idx_t CurrentTotalWeight() const { + return current_total_weight; } size_t Size() const { return entry_map.size(); } + bool IsEmpty() const { + return entry_map.empty(); + } private: struct Entry { shared_ptr value; idx_t memory; typename list::iterator lru_iterator; + // Record payload weight, which is used for global weight control. + unique_ptr payload; + idx_t payload_weight; }; using EntryMap = unordered_map; void DeleteImpl(typename EntryMap::iterator iter) { - current_memory -= iter->second.memory; + current_total_weight -= iter->second.payload_weight; + D_ASSERT(current_total_weight >= 0); lru_list.erase(iter->second.lru_iterator); entry_map.erase(iter); } - void EvictIfNeeded(idx_t required_memory) { - if (max_memory == 0) { + void EvictIfNeeded(idx_t required_weight) { + if (max_total_weight == 0) { return; } // Evict LRU entries until we have enough space - while (!lru_list.empty() && (current_memory + required_memory > max_memory)) { + while (!lru_list.empty() && (current_total_weight + required_weight > max_total_weight)) { const auto &stale_key = lru_list.back(); auto stale_it = entry_map.find(stale_key); if (stale_it != entry_map.end()) { @@ -136,8 +171,8 @@ class SharedLruCache { } } - const idx_t max_memory; - idx_t current_memory; + const idx_t max_total_weight; + idx_t current_total_weight; EntryMap entry_map; list lru_list; }; diff --git a/src/duckdb/src/include/duckdb/common/multi_file/multi_file_function.hpp b/src/duckdb/src/include/duckdb/common/multi_file/multi_file_function.hpp index d7777a052..13dbf15bf 100644 --- a/src/duckdb/src/include/duckdb/common/multi_file/multi_file_function.hpp +++ b/src/duckdb/src/include/duckdb/common/multi_file/multi_file_function.hpp @@ -122,7 +122,7 @@ class MultiFileFunction : public TableFunction { if (!result->file_options.union_by_name && bound_on_first_file) { file_string = result->file_list->GetFirstFile().path; } else { - for (auto &file : result->file_list->GetPaths()) { + for (auto &file : result->file_list->GetAllFiles()) { if (!file_string.empty()) { file_string += ","; } @@ -708,7 +708,22 @@ class MultiFileFunction : public TableFunction { const GlobalTableFunctionState *global_state) { auto &gstate = global_state->Cast(); - auto total_count = gstate.file_list.GetTotalFileCount(); + // get the file count - for >100 files we allow a lower bound to be given instead + auto count_info = gstate.file_list.GetFileCount(100); + while (count_info.type != FileExpansionType::ALL_FILES_EXPANDED) { + // the entire glob has not yet been expanded - we don't know how many files there are exactly + // we try to postpone expanding the glob by only expanding it once we have scanned 1% of the files + // check if we have reached AT LEAST 1% of progress + idx_t one_percent_min = count_info.count / 100; + if (gstate.completed_file_index < one_percent_min) { + // we have not - just report 0% + return 0.0; + } + // we have reached 1% given the currently known (incomplete) list of files + // retrieve more files to scan + count_info = gstate.file_list.GetFileCount(count_info.count + 1); + } + auto total_count = count_info.count; if (total_count == 0) { return 100.0; } @@ -754,7 +769,14 @@ class MultiFileFunction : public TableFunction { if (file_list_cardinality_estimate) { return file_list_cardinality_estimate; } - return data.interface->GetCardinality(data, data.file_list->GetTotalFileCount()); + // get the file count - for >500 files we allow an estimate + auto count_info = data.file_list->GetFileCount(500); + idx_t estimated_file_count = count_info.count; + if (count_info.type != FileExpansionType::ALL_FILES_EXPANDED) { + // not all files have been expanded - it's probably twice as many files + estimated_file_count *= 2; + } + return data.interface->GetCardinality(data, estimated_file_count); } static void MultiFileComplexFilterPushdown(ClientContext &context, LogicalGet &get, FunctionData *bind_data_p, @@ -776,7 +798,7 @@ class MultiFileFunction : public TableFunction { auto &bind_data = bind_data_p->Cast(); vector file_path; - for (const auto &file : bind_data.file_list->Files()) { + for (const auto &file : bind_data.file_list->GetDisplayFileList()) { file_path.emplace_back(file.path); } @@ -812,7 +834,7 @@ class MultiFileFunction : public TableFunction { result.insert(make_pair("Total Files Read", std::to_string(files_loaded))); constexpr size_t FILE_NAME_LIST_LIMIT = 5; - auto file_paths = gstate.file_list.GetPaths(); + auto file_paths = gstate.file_list.GetDisplayFileList(FILE_NAME_LIST_LIMIT + 1); if (!file_paths.empty()) { vector file_path_names; for (idx_t i = 0; i < MinValue(file_paths.size(), FILE_NAME_LIST_LIMIT); i++) { diff --git a/src/duckdb/src/include/duckdb/common/multi_file/multi_file_list.hpp b/src/duckdb/src/include/duckdb/common/multi_file/multi_file_list.hpp index ded5bad05..077076b14 100644 --- a/src/duckdb/src/include/duckdb/common/multi_file/multi_file_list.hpp +++ b/src/duckdb/src/include/duckdb/common/multi_file/multi_file_list.hpp @@ -17,26 +17,39 @@ namespace duckdb { class MultiFileList; enum class FileExpandResult : uint8_t { NO_FILES, SINGLE_FILE, MULTIPLE_FILES }; +enum class MultiFileListScanType { ALWAYS_FETCH, FETCH_IF_AVAILABLE }; + +enum class FileExpansionType { ALL_FILES_EXPANDED, NOT_ALL_FILES_KNOWN }; struct MultiFileListScanData { idx_t current_file_idx = DConstants::INVALID_INDEX; + MultiFileListScanType scan_type = MultiFileListScanType::ALWAYS_FETCH; +}; + +struct MultiFileCount { + explicit MultiFileCount(idx_t count, FileExpansionType type = FileExpansionType::ALL_FILES_EXPANDED) + : count(count), type(type) { + } + + idx_t count; + FileExpansionType type; }; class MultiFileListIterationHelper { public: - DUCKDB_API explicit MultiFileListIterationHelper(MultiFileList &collection); + DUCKDB_API explicit MultiFileListIterationHelper(const MultiFileList &collection); private: - MultiFileList &file_list; + const MultiFileList &file_list; private: class MultiFileListIterator; class MultiFileListIterator { public: - DUCKDB_API explicit MultiFileListIterator(MultiFileList *file_list); + DUCKDB_API explicit MultiFileListIterator(optional_ptr file_list); - optional_ptr file_list; + optional_ptr file_list; MultiFileListScanData file_scan_data; OpenFileInfo current_file; @@ -69,53 +82,50 @@ struct MultiFilePushdownInfo { //! NOTE: subclasses are responsible for ensuring thread-safety class MultiFileList { public: - MultiFileList(vector paths, FileGlobOptions options); - MultiFileList(vector paths, FileGlobInput input); + MultiFileList(); virtual ~MultiFileList(); - //! Returns the raw, unexpanded paths, pre-filter - const vector GetPaths() const; - //! Get Iterator over the files for pretty for loops - MultiFileListIterationHelper Files(); + MultiFileListIterationHelper Files() const; //! Initialize a sequential scan over a file list - void InitializeScan(MultiFileListScanData &iterator); + void InitializeScan(MultiFileListScanData &iterator) const; //! Scan the next file into result_file, returns false when out of files - bool Scan(MultiFileListScanData &iterator, OpenFileInfo &result_file); + bool Scan(MultiFileListScanData &iterator, OpenFileInfo &result_file) const; //! Returns the first file or an empty string if GetTotalFileCount() == 0 - OpenFileInfo GetFirstFile(); + OpenFileInfo GetFirstFile() const; //! Syntactic sugar for GetExpandResult() == FileExpandResult::NO_FILES - bool IsEmpty(); + bool IsEmpty() const; //! Virtual functions for subclasses public: virtual unique_ptr ComplexFilterPushdown(ClientContext &context, const MultiFileOptions &options, MultiFilePushdownInfo &info, - vector> &filters); + vector> &filters) const; virtual unique_ptr DynamicFilterPushdown(ClientContext &context, const MultiFileOptions &options, const vector &names, const vector &types, const vector &column_ids, TableFilterSet &filters) const; - virtual vector GetAllFiles() = 0; - virtual FileExpandResult GetExpandResult() = 0; - virtual idx_t GetTotalFileCount() = 0; + virtual vector GetAllFiles() const = 0; + virtual FileExpandResult GetExpandResult() const = 0; + //! Get the total file count - forces all files to be expanded / known so the exact count can be computed + virtual idx_t GetTotalFileCount() const = 0; + //! Get the file count - anything under "min_exact_count" is allowed to be incomplete (i.e. `NOT_ALL_FILES_KNOWN`) + //! This allows us to get a rough idea of the file count + virtual MultiFileCount GetFileCount(idx_t min_exact_count = 0) const; + virtual vector GetDisplayFileList(optional_idx max_files = optional_idx()) const; - virtual unique_ptr GetCardinality(ClientContext &context); - virtual unique_ptr Copy(); + virtual unique_ptr GetCardinality(ClientContext &context) const; + virtual unique_ptr Copy() const; protected: + //! Whether or not the file at the index is available instantly - or if this requires additional I/O + virtual bool FileIsAvailable(idx_t i) const; //! Get the i-th expanded file - virtual OpenFileInfo GetFile(idx_t i) = 0; - -protected: - //! The unexpanded input paths - const vector paths; - //! Whether paths can expand to 0 files - const FileGlobInput glob_input; + virtual OpenFileInfo GetFile(idx_t i) const = 0; public: template @@ -136,64 +146,73 @@ class SimpleMultiFileList : public MultiFileList { public: //! Construct a SimpleMultiFileList from a list of already expanded files explicit SimpleMultiFileList(vector paths); - //! Copy `paths` to `filtered_files` and apply the filters - unique_ptr ComplexFilterPushdown(ClientContext &context, const MultiFileOptions &options, - MultiFilePushdownInfo &info, - vector> &filters) override; - unique_ptr DynamicFilterPushdown(ClientContext &context, const MultiFileOptions &options, - const vector &names, const vector &types, - const vector &column_ids, - TableFilterSet &filters) const override; //! Main MultiFileList API - vector GetAllFiles() override; - FileExpandResult GetExpandResult() override; - idx_t GetTotalFileCount() override; + vector GetAllFiles() const override; + FileExpandResult GetExpandResult() const override; + idx_t GetTotalFileCount() const override; protected: //! Main MultiFileList API - OpenFileInfo GetFile(idx_t i) override; + OpenFileInfo GetFile(idx_t i) const override; + +protected: + //! The list of input paths + const vector paths; }; -//! MultiFileList that takes a list of paths and produces a list of files with all globs expanded -class GlobMultiFileList : public MultiFileList { +//! Lazily expanded MultiFileList +class LazyMultiFileList : public MultiFileList { public: - GlobMultiFileList(ClientContext &context, vector paths, FileGlobInput glob_input); - //! Calls ExpandAll, then prunes the expanded_files using the hive/filename filters - unique_ptr ComplexFilterPushdown(ClientContext &context, const MultiFileOptions &options, - MultiFilePushdownInfo &info, - vector> &filters) override; - unique_ptr DynamicFilterPushdown(ClientContext &context, const MultiFileOptions &options, - const vector &names, const vector &types, - const vector &column_ids, - TableFilterSet &filters) const override; + explicit LazyMultiFileList(optional_ptr context); - //! Main MultiFileList API - vector GetAllFiles() override; - FileExpandResult GetExpandResult() override; - idx_t GetTotalFileCount() override; + vector GetAllFiles() const override; + FileExpandResult GetExpandResult() const override; + idx_t GetTotalFileCount() const override; + MultiFileCount GetFileCount(idx_t min_exact_count = 0) const override; protected: - //! Main MultiFileList API - OpenFileInfo GetFile(idx_t i) override; + bool FileIsAvailable(idx_t i) const override; + OpenFileInfo GetFile(idx_t i) const override; - //! Get the i-th expanded file - OpenFileInfo GetFileInternal(idx_t i); - //! Grabs the next path and expands it into Expanded paths: returns false if no more files to expand - bool ExpandNextPath(); //! Grabs the next path and expands it into Expanded paths: returns false if no more files to expand - bool ExpandPathInternal(idx_t ¤t_path, vector &result) const; - //! Whether all files have been expanded - bool IsFullyExpanded() const; + virtual bool ExpandNextPath() const = 0; - //! The ClientContext for globbing - ClientContext &context; - //! The current path to expand - idx_t current_path; - //! The expanded files - vector expanded_files; +private: + bool ExpandNextPathInternal() const; +protected: mutable mutex lock; + //! The expanded files + mutable vector expanded_files; + //! Whether or not all files have been expanded + mutable bool all_files_expanded = false; + optional_ptr context; +}; + +//! MultiFileList that takes a list of globs and resolves all of the globs lazily into files +class GlobMultiFileList : public LazyMultiFileList { +public: + GlobMultiFileList(ClientContext &context, vector globs, FileGlobInput input); + + vector GetDisplayFileList(optional_idx max_files = optional_idx()) const override; + +protected: + bool ExpandNextPath() const override; + +protected: + //! The ClientContext for globbing + ClientContext &context; + //! The list of globs to expand + const vector globs; + //! Glob input + const FileGlobInput glob_input; + //! The current glob to expand + mutable idx_t current_glob; + //! File lists for the underlying globs + mutable vector> file_lists; + //! Current scan state + mutable MultiFileListScanData scan_state; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/opener_file_system.hpp b/src/duckdb/src/include/duckdb/common/opener_file_system.hpp index 265de2aff..b0a341aa6 100644 --- a/src/duckdb/src/include/duckdb/common/opener_file_system.hpp +++ b/src/duckdb/src/include/duckdb/common/opener_file_system.hpp @@ -9,6 +9,7 @@ #pragma once #include "duckdb/common/file_system.hpp" +#include "duckdb/common/multi_file/multi_file_list.hpp" namespace duckdb { @@ -21,6 +22,18 @@ class OpenerFileSystem : public FileSystem { void VerifyNoOpener(optional_ptr opener); void VerifyCanAccessDirectory(const string &path); void VerifyCanAccessFile(const string &path); + void VerifyCanAccessExtension(const string &path, const FileOpenFlags &flags) { + if (flags.OpenForWriting() && !flags.EnableExtensionInstall()) { + throw PermissionException( + "File '%s' cannot be opened for writing since files ending with '.duckdb_extension' are reserved for " + "DuckDB extensions, and these can only be installed through the INSTALL command", + path); + } + } + + bool IsDuckDBExtensionName(const string &path) { + return StringUtil::EndsWith(path, ".duckdb_extension"); + } void Read(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) override { GetFileSystem().Read(handle, buffer, nr_bytes, location); @@ -83,6 +96,13 @@ class OpenerFileSystem : public FileSystem { VerifyNoOpener(opener); VerifyCanAccessFile(source); VerifyCanAccessFile(target); + if (IsDuckDBExtensionName(target) && !IsDuckDBExtensionName(source)) { + throw PermissionException( + "File '%s' cannot be moved to '%s', files ending with '.duckdb_extension' are reserved for DuckDB " + "extensions, and these can only be installed through the INSTALL command, or moved if both are " + "extensions'", + source, target); + } GetFileSystem().MoveFile(source, target, GetOpener()); } @@ -150,6 +170,10 @@ class OpenerFileSystem : public FileSystem { GetFileSystem().UnregisterSubSystem(name); } + unique_ptr ExtractSubSystem(const string &name) override { + return GetFileSystem().ExtractSubSystem(name); + } + void SetDisabledFileSystems(const vector &names) override { GetFileSystem().SetDisabledFileSystems(names); } @@ -171,6 +195,9 @@ class OpenerFileSystem : public FileSystem { optional_ptr opener = nullptr) override { VerifyNoOpener(opener); VerifyCanAccessFile(file.path); + if (IsDuckDBExtensionName(file.path)) { + VerifyCanAccessExtension(file.path, flags); + } return GetFileSystem().OpenFile(file, flags, GetOpener()); } @@ -189,6 +216,22 @@ class OpenerFileSystem : public FileSystem { return true; } + unique_ptr GlobFilesExtended(const string &path, const FileGlobInput &input, + optional_ptr opener) override { + VerifyNoOpener(opener); + VerifyCanAccessFile(path); + return GetFileSystem().Glob(path, input, GetOpener()); + } + + bool SupportsGlobExtended() const override { + return true; + } + + string CanonicalizePath(const string &path_p, optional_ptr opener = nullptr) override { + VerifyNoOpener(opener); + return GetFileSystem().CanonicalizePath(path_p, GetOpener()); + } + private: void VerifyCanAccessFileInternal(const string &path, FileType type); }; diff --git a/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp b/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp index e495e9760..26dbad58c 100644 --- a/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp +++ b/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp @@ -1095,4 +1095,16 @@ struct CastFromPointer { template <> duckdb::string_t CastFromPointer::Operation(uintptr_t input, Vector &vector); +//===--------------------------------------------------------------------===// +// Types +//===--------------------------------------------------------------------===// +struct CastFromType { + template + static inline string_t Operation(SRC input, Vector &result) { + throw duckdb::NotImplementedException("Cast from pointer could not be performed!"); + } +}; +template <> +duckdb::string_t CastFromType::Operation(string_t input, Vector &vector); + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/operator/negate.hpp b/src/duckdb/src/include/duckdb/common/operator/negate.hpp new file mode 100644 index 000000000..f5b1f3f7b --- /dev/null +++ b/src/duckdb/src/include/duckdb/common/operator/negate.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "duckdb/common/limits.hpp" +#include "duckdb/common/exception.hpp" + +namespace duckdb { + +struct NegateOperator { + template + static bool CanNegate(T input) { + using Limits = NumericLimits; + return !(Limits::IsSigned() && Limits::Minimum() == input); + } + + template + static inline TR Operation(TA input) { + if (!CanNegate(input)) { + throw OutOfRangeException("Overflow in negation of numeric value!"); + } + return -(TR)input; + } +}; + +// Specialization for floating point (always negatable) +template <> +inline bool NegateOperator::CanNegate(float input) { + return true; +} +template <> +inline bool NegateOperator::CanNegate(double input) { + return true; +} + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/progress_bar/progress_bar.hpp b/src/duckdb/src/include/duckdb/common/progress_bar/progress_bar.hpp index b5c9c55df..e11f672a4 100644 --- a/src/duckdb/src/include/duckdb/common/progress_bar/progress_bar.hpp +++ b/src/duckdb/src/include/duckdb/common/progress_bar/progress_bar.hpp @@ -17,7 +17,7 @@ namespace duckdb { struct ClientConfig; -typedef unique_ptr (*progress_bar_display_create_func_t)(); +typedef std::function()> progress_bar_display_create_func_t; struct QueryProgress { friend class ProgressBar; diff --git a/src/duckdb/src/include/duckdb/common/row_operations/row_operations.hpp b/src/duckdb/src/include/duckdb/common/row_operations/row_operations.hpp index ee1d11afb..382b60dd2 100644 --- a/src/duckdb/src/include/duckdb/common/row_operations/row_operations.hpp +++ b/src/duckdb/src/include/duckdb/common/row_operations/row_operations.hpp @@ -18,9 +18,7 @@ class ArenaAllocator; struct AggregateObject; struct AggregateFilterData; class DataChunk; -class RowLayout; class TupleDataLayout; -class RowDataCollection; struct SelectionVector; class StringHeap; struct UnifiedVectorFormat; diff --git a/src/duckdb/src/include/duckdb/common/shared_ptr_ipp.hpp b/src/duckdb/src/include/duckdb/common/shared_ptr_ipp.hpp index 8668bbb4c..6b6d8dcc9 100644 --- a/src/duckdb/src/include/duckdb/common/shared_ptr_ipp.hpp +++ b/src/duckdb/src/include/duckdb/common/shared_ptr_ipp.hpp @@ -250,6 +250,18 @@ class shared_ptr { // NOLINT: invalid case style return internal >= other.internal; } + shared_ptr atomic_load() const { + return shared_ptr(std::atomic_load(&internal)); + } + + shared_ptr atomic_load(std::memory_order order) const { + return shared_ptr(std::atomic_load_explicit(&internal, order)); + } + + void atomic_store(const shared_ptr &new_ptr) { + std::atomic_store(&internal, new_ptr.internal); + } + private: // This overload is used when the class inherits from 'enable_shared_from_this' template static string ToString(const vector &input, const string &separator) { diff --git a/src/duckdb/src/include/duckdb/common/thread.hpp b/src/duckdb/src/include/duckdb/common/thread.hpp index 6c15a662b..277e34b39 100644 --- a/src/duckdb/src/include/duckdb/common/thread.hpp +++ b/src/duckdb/src/include/duckdb/common/thread.hpp @@ -11,18 +11,25 @@ #ifndef DUCKDB_NO_THREADS #include #include "duckdb/common/typedefs.hpp" +#include "duckdb/common/string.hpp" namespace duckdb { using std::thread; +using thread_id = std::thread::id; -} +} // namespace duckdb +#else +using thread_id = uint64_t; #endif namespace duckdb { struct ThreadUtil { static void SleepMs(idx_t ms); + static void SleepMicroSeconds(idx_t micros); + static thread_id GetThreadId(); + static string GetThreadIdString(); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types.hpp b/src/duckdb/src/include/duckdb/common/types.hpp index 343a4e4f0..b6e24805c 100644 --- a/src/duckdb/src/include/duckdb/common/types.hpp +++ b/src/duckdb/src/include/duckdb/common/types.hpp @@ -22,6 +22,7 @@ class Value; class TypeCatalogEntry; class Vector; class ClientContext; +class ParsedExpression; class CoordinateReferenceSystem; struct string_t; // NOLINT: mimic std casing @@ -186,8 +187,7 @@ enum class LogicalTypeId : uint8_t { SQLNULL = 1, /* NULL type, used for constant NULL */ UNKNOWN = 2, /* unknown type, used for parameter expressions */ ANY = 3, /* ANY type, used for functions that accept any type as parameter */ - USER = 4, /* A User Defined Type (e.g., ENUMs before the binder) */ - + UNBOUND = 4, /* A parsed but unbound type, used during query planning */ // A "template" type functions as a "placeholder" type for function arguments and return types. // Templates only exist during the binding phase, in the scope of a function, and are replaced with concrete types @@ -196,6 +196,8 @@ enum class LogicalTypeId : uint8_t { // name are always resolved to the same concrete type. TEMPLATE = 5, + TYPE = 6, /* Type type, used for type parameters */ + BOOLEAN = 10, TINYINT = 11, SMALLINT = 12, @@ -284,6 +286,9 @@ struct LogicalType { inline bool IsUnknown() const { return id_ == LogicalTypeId::UNKNOWN; } + inline bool IsUnbound() const { + return id_ == LogicalTypeId::UNBOUND; + } inline shared_ptr GetAuxInfoShrPtr() const { return type_info_; @@ -352,6 +357,7 @@ struct LogicalType { //! Returns the maximum logical type when combining the two types - or throws an exception if combining is not possible DUCKDB_API static LogicalType MaxLogicalType(ClientContext &context, const LogicalType &left, const LogicalType &right); DUCKDB_API static bool TryGetMaxLogicalType(ClientContext &context, const LogicalType &left, const LogicalType &right, LogicalType &result); + DUCKDB_API static bool TryGetMaxLogicalTypeUnchecked(const LogicalType &left, const LogicalType &right, LogicalType &result); //! Forcibly returns a maximum logical type - similar to MaxLogicalType but never throws. As a fallback either left or right are returned. DUCKDB_API static LogicalType ForceMaxLogicalType(const LogicalType &left, const LogicalType &right); //! Normalize a type - removing literals @@ -444,9 +450,8 @@ struct LogicalType { DUCKDB_API static LogicalType INTEGER_LITERAL(const Value &constant); // NOLINT // DEPRECATED - provided for backwards compatibility DUCKDB_API static LogicalType ENUM(const string &enum_name, Vector &ordered_data, idx_t size); // NOLINT - DUCKDB_API static LogicalType USER(const string &user_type_name); // NOLINT - DUCKDB_API static LogicalType USER(const string &user_type_name, const vector &user_type_mods); // NOLINT - DUCKDB_API static LogicalType USER(string catalog, string schema, string name, vector user_type_mods); // NOLINT + DUCKDB_API static LogicalType UNBOUND(unique_ptr expr); // NOLINT + DUCKDB_API static LogicalType TYPE(); // NOLINT //! A list of all NUMERIC types (integral and floating point types) DUCKDB_API static const vector Numeric(); //! A list of all INTEGRAL types @@ -477,12 +482,12 @@ struct ListType { DUCKDB_API static const LogicalType &GetChildType(const LogicalType &type); }; -struct UserType { - DUCKDB_API static const string &GetCatalog(const LogicalType &type); - DUCKDB_API static const string &GetSchema(const LogicalType &type); - DUCKDB_API static const string &GetTypeName(const LogicalType &type); - DUCKDB_API static const vector &GetTypeModifiers(const LogicalType &type); - DUCKDB_API static vector &GetTypeModifiers(LogicalType &type); + +struct UnboundType { + // Try to bind the unbound type into a concrete type, using just the built in types + DUCKDB_API static LogicalType TryParseAndDefaultBind(const string &type_str); + DUCKDB_API static LogicalType TryDefaultBind(const LogicalType &unbound_type); + DUCKDB_API static const unique_ptr &GetTypeExpression(const LogicalType &type); }; struct EnumType { @@ -557,8 +562,6 @@ DUCKDB_API string LogicalTypeIdToString(LogicalTypeId type); DUCKDB_API LogicalTypeId TransformStringToLogicalTypeId(const string &str); -DUCKDB_API LogicalType TransformStringToLogicalType(const string &str); - DUCKDB_API LogicalType TransformStringToLogicalType(const string &str, ClientContext &context); //! The PhysicalType used by the row identifiers column diff --git a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_iterators.hpp b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_iterators.hpp index ff42eadf2..d1d7d87ee 100644 --- a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_iterators.hpp +++ b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_iterators.hpp @@ -26,12 +26,14 @@ class ColumnDataChunkIterationHelper { class ColumnDataChunkIterator { public: - DUCKDB_API explicit ColumnDataChunkIterator(const ColumnDataCollection *collection_p, - vector column_ids); + DUCKDB_API ColumnDataChunkIterator(optional_ptr collection_p, + vector column_ids); + //! enable move constructor + DUCKDB_API ColumnDataChunkIterator(ColumnDataChunkIterator &&other) noexcept; - const ColumnDataCollection *collection; + optional_ptr collection; ColumnDataScanState scan_state; - shared_ptr scan_chunk; + unique_ptr scan_chunk; idx_t row_index; public: diff --git a/src/duckdb/src/include/duckdb/common/types/geometry.hpp b/src/duckdb/src/include/duckdb/common/types/geometry.hpp index 1fcc9d7a1..65fff18d6 100644 --- a/src/duckdb/src/include/duckdb/common/types/geometry.hpp +++ b/src/duckdb/src/include/duckdb/common/types/geometry.hpp @@ -35,6 +35,7 @@ struct VertexXY { static constexpr auto TYPE = VertexType::XY; static constexpr auto HAS_Z = false; static constexpr auto HAS_M = false; + static constexpr auto WIDTH = 2; double x; double y; @@ -48,6 +49,7 @@ struct VertexXYZ { static constexpr auto TYPE = VertexType::XYZ; static constexpr auto HAS_Z = true; static constexpr auto HAS_M = false; + static constexpr auto WIDTH = 3; double x; double y; @@ -61,6 +63,7 @@ struct VertexXYM { static constexpr auto TYPE = VertexType::XYM; static constexpr auto HAS_M = true; static constexpr auto HAS_Z = false; + static constexpr auto WIDTH = 3; double x; double y; @@ -75,6 +78,7 @@ struct VertexXYZM { static constexpr auto TYPE = VertexType::XYZM; static constexpr auto HAS_Z = true; static constexpr auto HAS_M = true; + static constexpr auto WIDTH = 4; double x; double y; @@ -219,6 +223,17 @@ class Geometry { //! Update the bounding box, return number of vertices processed DUCKDB_API static uint32_t GetExtent(const string_t &wkb, GeometryExtent &extent); + DUCKDB_API static uint32_t GetExtent(const string_t &wkb, GeometryExtent &extent, bool &has_any_empty); + + //! Convert to vectorized format + DUCKDB_API static void ToVectorizedFormat(Vector &source, Vector &target, idx_t count, GeometryType geom_type, + VertexType vert_type); + //! Convert from vectorized format + DUCKDB_API static void FromVectorizedFormat(Vector &source, Vector &target, idx_t count, GeometryType geom_type, + VertexType vert_type, idx_t result_offset); + + //! Get the vectorized logical type for a given geometry and vertex type + DUCKDB_API static LogicalType GetVectorizedType(GeometryType geom_type, VertexType vert_type); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/geometry_crs.hpp b/src/duckdb/src/include/duckdb/common/types/geometry_crs.hpp index 62951b30a..6475a800d 100644 --- a/src/duckdb/src/include/duckdb/common/types/geometry_crs.hpp +++ b/src/duckdb/src/include/duckdb/common/types/geometry_crs.hpp @@ -20,24 +20,28 @@ class Serializer; class Deserializer; enum class CoordinateReferenceSystemType : uint8_t { - //! Unknown + //! Not set / invalid INVALID = 0, //! Opaque identifier SRID = 1, + //! AUTH:CODE format + AUTH_CODE = 2, //! PROJJSON format - PROJJSON = 2, + PROJJSON = 3, //! WKT2_2019 format - WKT2_2019 = 3, - //! AUTH:CODE format - AUTH_CODE = 4, + WKT2_2019 = 4, }; class CoordinateReferenceSystem { + friend class CoordinateReferenceSystemProvider; + public: CoordinateReferenceSystem() = default; - //! Equivalent to calling "TryParse" and throwing an exception on failure - explicit CoordinateReferenceSystem(const string &crs); + explicit CoordinateReferenceSystem(const string &definition) { + ParseDefinition(definition, *this); + } + //! Get the identified type of the coordinate reference system CoordinateReferenceSystemType GetType() const { return type; @@ -45,84 +49,88 @@ class CoordinateReferenceSystem { //! Get the full provided definition of the coordinate reference system const string &GetDefinition() const { - return text; + return definition; } - //! Get the "friendly name" of the coordinate reference system - //! This can be empty if no name could be determined from the definition - const string &GetName() const { - return name; + //! Get the "identifier" of the coordinate reference system (e.g. "EPSG:4326") + //! This is the same as the definition for AUTH:CODE and SRID types + const string &GetIdentifier() const { + return identifier.empty() ? definition : identifier; } - //! Get the "code" of the coordinate reference system (e.g. "EPSG:4326") - //! This can be empty if no id could be determined from the definition - const string &GetCode() const { - return code; - } - - //! Get the best available "display" name for this CRS - //! This is the first non-empty value of "code", "name" and "definition" - const string &GetDisplayName() const { - if (!code.empty()) { - return code; - } - if (!name.empty()) { - return name; + //! Is this a fully-defined coordinate system? + bool IsComplete() const { + switch (GetType()) { + case CoordinateReferenceSystemType::PROJJSON: + case CoordinateReferenceSystemType::WKT2_2019: + return true; + default: + return false; } - return text; } //! Attempt to determine if this CRS is equivalent to another CRS //! This is currently not very precise, and may yield false negatives //! We consider two CRSs equal if one of the following is true: - //! - Their codes match (if both have a code) - //! - Their names match (if both have a name) + //! - Their identifiers match //! - Their type and full text definitions match, character-for-character bool Equals(const CoordinateReferenceSystem &other) const { - if (!code.empty() && code == other.code) { - // Whatever the definitions are, if the codes match we consider them equal + // Whatever the definitions are, if the identifiers match we consider them equal + if (!identifier.empty() && identifier == other.identifier) { return true; } - if (!name.empty() && name == other.name) { - // Whatever the definitions are, if the names match we consider them equal - return true; - } - // Finally, fall back to comparing the full definitions + + // Fall back to comparing the full definitions // This is not ideal, because the same CRS (in the same format!) can often be expressed in multiple ways // E.g. field order, whitespace differences, casing, etc. But it's better than nothing for now. // In the future we should: // 1. Implement proper normalization for each CRS format, and make _structured_ comparisons // 2. Allow extensions to inject a CRS handling library (e.g. PROJ) to perform proper _semantic_ comparisons - return type == other.type && text == other.text; + return type == other.type && definition == other.definition; } + //! Try to identify a CRS from a string + //! If the string is unable to be identified as one of the registered coordinates systems, and + //! - IS NOT a complete CRS definition, returns nullptr + //! - IS a complete CRS definition (e.g. PROJJSON or WKT2), returns the CRS as is. + //! Otherwise, returns the identified CRS in the most compact form possible (AUTH:CODE > SRID > PROJJSON > WKT2) + static unique_ptr TryIdentify(ClientContext &context, const string &source_crs); + + //! Try to convert the CRS to another format + //! Returns nullptr if no conversion could be performed + static unique_ptr TryConvert(ClientContext &context, + const CoordinateReferenceSystem &source_crs, + CoordinateReferenceSystemType target_type); + + //! Try to convert the CRS to another format + //! Returns nullptr if no conversion could be performed + static unique_ptr TryConvert(ClientContext &context, const string &source_crs, + CoordinateReferenceSystemType target_type); + + //! Serialize this CRS to a binary format void Serialize(Serializer &serializer) const; - static CoordinateReferenceSystem Deserialize(Deserializer &deserializer); -public: - static bool TryParse(const string &text, CoordinateReferenceSystem &result); - static void Parse(const string &text, CoordinateReferenceSystem &result); + //! Deserialize a CRS from a binary format + static CoordinateReferenceSystem Deserialize(Deserializer &deserializer); private: + static void ParseDefinition(const string &text, CoordinateReferenceSystem &result); static bool TryParseAuthCode(const string &text, CoordinateReferenceSystem &result); static bool TryParseWKT2(const string &text, CoordinateReferenceSystem &result); static bool TryParsePROJJSON(const string &text, CoordinateReferenceSystem &result); +private: //! The type of the coordinate reference system CoordinateReferenceSystemType type = CoordinateReferenceSystemType::INVALID; //! The text definition of the coordinate reference system //! E.g. "AUTH:CODE", or a PROJJSON or WKT2 string - string text; - - //! The "friendly name" of the coordinate reference system - //! This can often be extracted from the definition, but is cached here for convenience - string name; + string definition; - //! The "code" of the coordinate reference system (e.g. "EPSG:4326") - //! This can often be extracted from the definition, but is cached here for convenience - string code; + //! The identifier code of the coordinate reference system + //! This can usually be derived from the text definition, but is cached here for convenience + string identifier; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/null_value.hpp b/src/duckdb/src/include/duckdb/common/types/null_value.hpp index ed96b721a..9cf57f944 100644 --- a/src/duckdb/src/include/duckdb/common/types/null_value.hpp +++ b/src/duckdb/src/include/duckdb/common/types/null_value.hpp @@ -27,11 +27,12 @@ inline T NullValue() { return std::numeric_limits::min(); } -constexpr const char str_nil[2] = {'\200', '\0'}; +//! This could be two bytes but then GCC gives a warning when it's copied +constexpr const char str_nil[4] = {'\200', '\0', '\0', '\0'}; template <> inline const char *NullValue() { - D_ASSERT(str_nil[0] == '\200' && str_nil[1] == '\0'); + D_ASSERT(str_nil[0] == '\200' && str_nil[1] == '\0' && str_nil[2] == '\0' && str_nil[3] == '\0'); return str_nil; } diff --git a/src/duckdb/src/include/duckdb/common/types/row/row_data_collection.hpp b/src/duckdb/src/include/duckdb/common/types/row/row_data_collection.hpp deleted file mode 100644 index 74196f00c..000000000 --- a/src/duckdb/src/include/duckdb/common/types/row/row_data_collection.hpp +++ /dev/null @@ -1,132 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/common/types/row/row_data_collection.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/common/types/vector.hpp" -#include "duckdb/storage/buffer_manager.hpp" -#include "duckdb/storage/buffer/block_handle.hpp" - -namespace duckdb { - -struct RowDataBlock { -public: - RowDataBlock(MemoryTag tag, BufferManager &buffer_manager, idx_t capacity, idx_t entry_size) - : capacity(capacity), entry_size(entry_size), count(0), byte_offset(0) { - auto size = MaxValue(buffer_manager.GetBlockSize(), capacity * entry_size); - auto buffer_handle = buffer_manager.Allocate(tag, size, false); - block = buffer_handle.GetBlockHandle(); - D_ASSERT(BufferManager::GetAllocSize(size + block->block_manager.GetBlockHeaderSize()) == - block->GetMemoryUsage()); - } - - explicit RowDataBlock(idx_t entry_size) : entry_size(entry_size) { - } - //! The buffer block handle - shared_ptr 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; - -private: - //! Implicit copying is not allowed - RowDataBlock(const RowDataBlock &) = delete; - -public: - unique_ptr Copy() { - auto result = make_uniq(entry_size); - result->block = block; - result->capacity = capacity; - result->count = count; - result->byte_offset = byte_offset; - return result; - } -}; - -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); - - unique_ptr CloneEmpty(bool keep_pinned = false) const { - return make_uniq(buffer_manager, block_capacity, entry_size, keep_pinned); - } - - //! 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> blocks; - //! The blocks that this collection currently has pinned - vector pinned_blocks; - //! Whether the blocks should stay pinned (necessary for e.g. a heap) - const bool keep_pinned; - -public: - idx_t AppendToBlock(RowDataBlock &block, BufferHandle &handle, vector &append_entries, - idx_t remaining, idx_t entry_sizes[]); - RowDataBlock &CreateBlock(); - vector Build(idx_t added_count, data_ptr_t key_locations[], idx_t entry_sizes[], - const SelectionVector *sel = FlatVector::IncrementalSelectionVector()); - - void Merge(RowDataCollection &other); - - void Clear() { - blocks.clear(); - pinned_blocks.clear(); - count = 0; - } - - //! The size (in bytes) of this RowDataCollection - idx_t SizeInBytes() const { - VerifyBlockSizes(); - idx_t size = 0; - for (auto &block : blocks) { - size += block->block->GetMemoryUsage(); - } - return size; - } - - //! Verifies that the block sizes are correct (Debug only) - void VerifyBlockSizes() const { -#ifdef DEBUG - for (auto &block : blocks) { - D_ASSERT(block->block->GetMemoryUsage() == - BufferManager::GetAllocSize(block->capacity * entry_size + Storage::DEFAULT_BLOCK_HEADER_SIZE)); - } -#endif - } - - static inline idx_t EntriesPerBlock(const idx_t width, const idx_t block_size) { - return block_size / width; - } - -private: - mutex rdc_lock; - - //! Copying is not allowed - RowDataCollection(const RowDataCollection &) = delete; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/row/row_data_collection_scanner.hpp b/src/duckdb/src/include/duckdb/common/types/row/row_data_collection_scanner.hpp deleted file mode 100644 index b805c0955..000000000 --- a/src/duckdb/src/include/duckdb/common/types/row/row_data_collection_scanner.hpp +++ /dev/null @@ -1,123 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/common/types/row/row_data_collection_scanner.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/types.hpp" -#include "duckdb/common/types/row/row_layout.hpp" - -namespace duckdb { - -class BufferHandle; -class RowDataCollection; -struct RowDataBlock; -class DataChunk; - -//! Used to scan the data into DataChunks after sorting -struct RowDataCollectionScanner { -public: - using Types = vector; - - struct ScanState { - explicit ScanState(const RowDataCollectionScanner &scanner_p) : scanner(scanner_p), block_idx(0), entry_idx(0) { - } - - void PinData(); - - //! The data layout - const RowDataCollectionScanner &scanner; - - idx_t block_idx; - idx_t entry_idx; - - BufferHandle data_handle; - BufferHandle heap_handle; - - // We must pin ALL blocks we are going to gather from - vector pinned_blocks; - }; - - //! Ensure that heap blocks correspond to row blocks - static void AlignHeapBlocks(RowDataCollection &dst_block_collection, RowDataCollection &dst_string_heap, - RowDataCollection &src_block_collection, RowDataCollection &src_string_heap, - const RowLayout &layout); - - RowDataCollectionScanner(RowDataCollection &rows, RowDataCollection &heap, const RowLayout &layout, bool external, - bool flush = true); - - // Single block scan - RowDataCollectionScanner(RowDataCollection &rows, RowDataCollection &heap, const RowLayout &layout, bool external, - idx_t block_idx, bool flush); - - //! The type layout of the payload - inline const vector &GetTypes() const { - return layout.GetTypes(); - } - - //! The number of rows in the collection - inline idx_t Count() const { - return total_count; - } - - //! 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; - } - - //! The number of remaining rows - inline idx_t BlockIndex() const { - return read_state.block_idx; - } - - //! Swizzle the blocks for external scanning - //! Swizzling is all or nothing, so if we have scanned previously, - //! we need to re-swizzle. - void ReSwizzle(); - - void SwizzleBlock(idx_t block_idx); - - //! Scans the next data chunk from the sorted data - void Scan(DataChunk &chunk); - - //! Resets to the start and updates the flush flag - void Reset(bool flush = true); - -private: - //! The row data being scanned - RowDataCollection &rows; - //! The row heap being scanned - RowDataCollection &heap; - //! The data layout - const RowLayout layout; - //! Read state - ScanState read_state; - //! The total count of sorted_data - idx_t total_count; - //! The number of rows scanned so far - idx_t total_scanned; - //! Addresses used to gather from the sorted data - Vector addresses = Vector(LogicalType::POINTER); - //! Whether the blocks can be flushed to disk - const bool external; - //! Whether to flush the blocks after scanning - bool flush; - //! Whether we are unswizzling the blocks - const bool unswizzling; - - //! Swizzle a single block - void SwizzleBlockInternal(RowDataBlock &data_block, RowDataBlock &heap_block); - //! Checks that the newest block is valid - void ValidateUnscannedBlock() const; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/row/row_layout.hpp b/src/duckdb/src/include/duckdb/common/types/row/row_layout.hpp deleted file mode 100644 index 702cba4d2..000000000 --- a/src/duckdb/src/include/duckdb/common/types/row/row_layout.hpp +++ /dev/null @@ -1,82 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/common/types/row/row_layout.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/common/types/validity_mask.hpp" -#include "duckdb/execution/operator/aggregate/aggregate_object.hpp" -#include "duckdb/planner/expression.hpp" - -namespace duckdb { - -class RowLayout { -public: - friend class TupleDataLayout; - using ValidityBytes = TemplatedValidityMask; - - //! Creates an empty RowLayout - RowLayout(); - -public: - //! Initializes the RowLayout with the specified types to an empty RowLayout - void Initialize(vector types, 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 &GetTypes() const { - return types; - } - //! 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 column offsets into each row - inline const vector &GetOffsets() const { - return offsets; - } - //! Returns whether all columns in this layout are constant size - inline bool AllConstant() const { - return all_constant; - } - inline idx_t GetHeapOffset() const { - return heap_pointer_offset; - } - -private: - //! The types of the data columns - vector types; - //! The width of the validity header - idx_t flag_width; - //! The width of the data portion - idx_t data_width; - //! The width of the entire row - idx_t row_width; - //! The offsets to the columns and aggregate data in each row - vector 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 diff --git a/src/duckdb/src/include/duckdb/common/types/type_manager.hpp b/src/duckdb/src/include/duckdb/common/types/type_manager.hpp new file mode 100644 index 000000000..2347bba75 --- /dev/null +++ b/src/duckdb/src/include/duckdb/common/types/type_manager.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "duckdb/common/types.hpp" +#include "duckdb/common/types/string.hpp" + +namespace duckdb { + +class ClientContext; +class DatabaseInstance; +class CastFunctionSet; +struct DBConfig; + +class TypeManager { +public: + explicit TypeManager(DBConfig &config); + + ~TypeManager(); + + //! Get the CastFunctionSet from the TypeManager + CastFunctionSet &GetCastFunctions(); + + //! Try to parse and bind a logical type from a string. Throws an exception if the type could not be parsed. + LogicalType ParseLogicalType(const string &type_str, ClientContext &context) const; + + //! Get the TypeManager from the DatabaseInstance + static TypeManager &Get(DatabaseInstance &db); + static TypeManager &Get(ClientContext &context); + +private: + //! This has to be a function pointer to avoid the compiler inlining the implementation and + //! blowing up the binary size of extensions that include type_manager.hpp + LogicalType (*parse_function)(const string &, ClientContext &); + + //! The set of cast functions + unique_ptr cast_functions; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/value.hpp b/src/duckdb/src/include/duckdb/common/types/value.hpp index 4b54a64d5..b93f5e5b7 100644 --- a/src/duckdb/src/include/duckdb/common/types/value.hpp +++ b/src/duckdb/src/include/duckdb/common/types/value.hpp @@ -36,6 +36,7 @@ class Value { friend struct UnionValue; friend struct ArrayValue; friend struct MapValue; + friend struct TypeValue; public: //! Create an empty NULL value of the specified type @@ -204,6 +205,9 @@ class Value { DUCKDB_API static Value GEOMETRY(const_data_ptr_t data, idx_t len); DUCKDB_API static Value GEOMETRY(const_data_ptr_t data, idx_t len, const CoordinateReferenceSystem &crs); + DUCKDB_API static Value TYPE(const LogicalType &type); + DUCKDB_API static Value TYPE(const string_t &serialized_type); + //! Creates an aggregate state DUCKDB_API static Value AGGREGATE_STATE(const LogicalType &type, const_data_ptr_t data, idx_t len); // NOLINT @@ -468,6 +472,10 @@ struct UnionValue { DUCKDB_API static const LogicalType &GetType(const Value &value); }; +struct TypeValue { + DUCKDB_API static LogicalType GetType(const Value &value); +}; + //! Return the internal integral value for any type that is stored as an integral value internally //! This can be used on values of type integer, uinteger, but also date, timestamp, decimal, etc struct IntegralValue { diff --git a/src/duckdb/src/include/duckdb/common/types/variant.hpp b/src/duckdb/src/include/duckdb/common/types/variant.hpp index 280c9e695..4db6007b0 100644 --- a/src/duckdb/src/include/duckdb/common/types/variant.hpp +++ b/src/duckdb/src/include/duckdb/common/types/variant.hpp @@ -17,9 +17,18 @@ struct UnifiedVariantVector; struct RecursiveUnifiedVectorFormat; struct UnifiedVectorFormat; -enum class VariantChildLookupMode : uint8_t { BY_KEY, BY_INDEX }; +enum class VariantChildLookupMode : uint8_t { INVALID, BY_KEY, BY_INDEX }; struct VariantPathComponent { +public: + explicit VariantPathComponent() : lookup_mode(VariantChildLookupMode::INVALID) { + } + explicit VariantPathComponent(const string &key) : lookup_mode(VariantChildLookupMode::BY_KEY), key(key) { + } + explicit VariantPathComponent(uint32_t index) : lookup_mode(VariantChildLookupMode::BY_INDEX), index(index) { + } + +public: VariantChildLookupMode lookup_mode; string key; uint32_t index; @@ -30,8 +39,6 @@ struct VariantNestedData { uint32_t child_count; //! Index of the first child uint32_t children_idx; - //! Whether the row is null - bool is_null; }; struct VariantDecimalData { diff --git a/src/duckdb/src/include/duckdb/common/virtual_file_system.hpp b/src/duckdb/src/include/duckdb/common/virtual_file_system.hpp index e1b978ba7..17b59af59 100644 --- a/src/duckdb/src/include/duckdb/common/virtual_file_system.hpp +++ b/src/duckdb/src/include/duckdb/common/virtual_file_system.hpp @@ -14,12 +14,14 @@ #include "duckdb/main/extension_helper.hpp" namespace duckdb { +struct FileSystemRegistry; // bunch of wrappers to allow registering protocol handlers class VirtualFileSystem : public FileSystem { public: VirtualFileSystem(); explicit VirtualFileSystem(unique_ptr &&inner_file_system); + ~VirtualFileSystem() override; void Read(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) override; void Write(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) override; @@ -51,14 +53,9 @@ class VirtualFileSystem : public FileSystem { bool TryRemoveFile(const string &filename, optional_ptr opener) override; void RemoveFiles(const vector &filenames, optional_ptr opener) override; - vector Glob(const string &path, FileOpener *opener = nullptr) override; - void RegisterSubSystem(unique_ptr fs) override; - - void UnregisterSubSystem(const string &name) override; - void RegisterSubSystem(FileCompressionType compression_type, unique_ptr fs) override; - + void UnregisterSubSystem(const string &name) override; unique_ptr ExtractSubSystem(const string &name) override; vector ListSubSystems() override; @@ -71,6 +68,8 @@ class VirtualFileSystem : public FileSystem { string PathSeparator(const string &path) override; + string CanonicalizePath(const string &path_p, optional_ptr opener) override; + protected: unique_ptr OpenFileExtended(const OpenFileInfo &file, FileOpenFlags flags, optional_ptr opener) override; @@ -85,17 +84,22 @@ class VirtualFileSystem : public FileSystem { return true; } + unique_ptr GlobFilesExtended(const string &path, const FileGlobInput &input, + optional_ptr opener) override; + bool SupportsGlobExtended() const override { + return true; + } + private: FileSystem &FindFileSystem(const string &path, optional_ptr file_opener); - FileSystem &FindFileSystem(const string &path, optional_ptr database_instance); - FileSystem &FindFileSystem(const string &path); - optional_ptr FindFileSystemInternal(const string &path); + FileSystem &FindFileSystem(shared_ptr ®istry, const string &path, + optional_ptr file_opener); + optional_ptr FindFileSystemInternal(FileSystemRegistry ®istry, const string &path); private: - vector> sub_systems; - map> compressed_fs; - const unique_ptr default_fs; - unordered_set disabled_file_systems; + mutex registry_lock; + shared_ptr file_system_registry; + vector> unregistered_file_systems; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/windows_undefs.hpp b/src/duckdb/src/include/duckdb/common/windows_undefs.hpp index da4c3f1fc..4695fa9b9 100644 --- a/src/duckdb/src/include/duckdb/common/windows_undefs.hpp +++ b/src/duckdb/src/include/duckdb/common/windows_undefs.hpp @@ -47,4 +47,8 @@ #undef interface #endif +#ifdef DELETE +#undef DELETE +#endif + #endif diff --git a/src/duckdb/src/include/duckdb/execution/expression_executor_state.hpp b/src/duckdb/src/include/duckdb/execution/expression_executor_state.hpp index 112e76109..fdccac78c 100644 --- a/src/duckdb/src/include/duckdb/execution/expression_executor_state.hpp +++ b/src/duckdb/src/include/duckdb/execution/expression_executor_state.hpp @@ -41,6 +41,9 @@ struct ExpressionState { void Verify(ExpressionExecutorState &root); + //! Reset any cached dictionary expression states in this expression state and its children + virtual void ResetDictionaryStates(); + public: template TARGET &Cast() { @@ -67,6 +70,8 @@ struct ExecuteFunctionState : public ExpressionState { bool TryExecuteDictionaryExpression(const BoundFunctionExpression &expr, DataChunk &args, ExpressionState &state, Vector &result); + void ResetDictionaryStates() override; + public: unique_ptr local_state; diff --git a/src/duckdb/src/include/duckdb/execution/index/art/art.hpp b/src/duckdb/src/include/duckdb/execution/index/art/art.hpp index 09e10aa80..357a4781b 100644 --- a/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/art/art.hpp @@ -45,8 +45,6 @@ class ART : public BoundIndex { static constexpr uint8_t ALLOCATOR_COUNT = 9; //! FixedSizeAllocator count of deprecated ARTs. static constexpr uint8_t DEPRECATED_ALLOCATOR_COUNT = ALLOCATOR_COUNT - 3; - //! Keys must not exceed MAX_KEY_LEN * prefix_count. - static constexpr idx_t MAX_KEY_LEN = 8192; public: ART(const string &name, const IndexConstraintType index_constraint_type, const vector &column_ids, @@ -70,8 +68,6 @@ class ART : public BoundIndex { shared_ptr, ALLOCATOR_COUNT>> allocators; //! True, if the ART owns its data. bool owns_data; - //! True, if keys need a key length verification pass. - bool verify_max_key_len; public: //! Try to initialize a scan on the ART with the given expression and filter. @@ -81,6 +77,20 @@ class ART : public BoundIndex { //! If all row IDs were fetched, it return true, else false. bool Scan(IndexScanState &state, idx_t max_count, set &row_ids); + //! Simple merge: scan source ART and delete each (key, rowid) from this ART. + // FIXME: replace with structural tree delete merge. + void RemovalMerge(IndexLock &state, BoundIndex &source_index); + //! Obtains a lock and calls RemovalMerge while holding that lock. + void RemovalMerge(BoundIndex &source_index); + //! Simple merge: scan source ART and insert each (key, rowid) into this ART. + //! Returns error data if constraint violation. + // FIXME: This is only used in MergeCheckpointDeltas, and even then it is used in lieu of the existing + // MergeIndexes which don't support deprecated leaf chains. Once support for that is added, this simpler insert + // merge may be removed. + ErrorData InsertMerge(IndexLock &state, BoundIndex &source_index, IndexAppendMode append_mode); + //! Obtains a lock and calls InsertMerge while holding that lock. + ErrorData InsertMerge(BoundIndex &source_index, IndexAppendMode append_mode); + //! Appends data to the locked index. ErrorData Append(IndexLock &l, DataChunk &chunk, Vector &row_ids) override; //! Appends data to the locked index and verifies constraint violations. @@ -88,8 +98,13 @@ class ART : public BoundIndex { //! Insert a chunk. ErrorData Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids) override; - //! Insert a chunk and verifies constraint violations. + //! Insert a chunk and verify constraint violations (generates keys and calls InsertKeys which does the + //! verification). ErrorData Insert(IndexLock &l, DataChunk &data, Vector &row_ids, IndexAppendInfo &info) override; + //! Insert keys and row_ids into ART and verify constraint violations. + ErrorData InsertKeys(ArenaAllocator &arena, unsafe_vector &keys, unsafe_vector &row_id_keys, + idx_t count, const DeleteIndexInfo &delete_info, IndexAppendMode append_mode, + optional_ptr chunk = nullptr); //! Verify that data can be appended to the index without a constraint violation. void VerifyAppend(DataChunk &chunk, IndexAppendInfo &info, optional_ptr manager) override; @@ -97,6 +112,11 @@ class ART : public BoundIndex { //! Delete a chunk from the ART. idx_t TryDelete(IndexLock &state, DataChunk &entries, Vector &row_identifiers, optional_ptr deleted_sel, optional_ptr non_deleted_sel) override; + //! Delete keys and row_ids from the ART. + idx_t DeleteKeys(unsafe_vector &keys, unsafe_vector &row_id_keys, idx_t count, + optional_ptr deleted_sel = nullptr, + optional_ptr non_deleted_sel = nullptr); + //! Drop the ART. void CommitDrop(IndexLock &index_lock) override; diff --git a/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp b/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp index 49793f364..5b3715cfb 100644 --- a/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp @@ -50,6 +50,12 @@ class ARTKey { key.len = sizeof(value); } + static inline ARTKey CreateARTKeyFromBytes(ArenaAllocator &allocator, const_data_ptr_t data, idx_t len) { + auto new_data = allocator.Allocate(len); + memcpy(new_data, data, len); + return ARTKey(new_data, len); + } + static ARTKey CreateKey(ArenaAllocator &allocator, PhysicalType type, Value &value); public: @@ -73,7 +79,6 @@ class ARTKey { void Concat(ArenaAllocator &allocator, const ARTKey &other); row_t GetRowId() const; idx_t GetMismatchPos(const ARTKey &other, const idx_t start) const; - void VerifyKeyLength(const idx_t max_len) const; private: template diff --git a/src/duckdb/src/include/duckdb/execution/index/art/iterator.hpp b/src/duckdb/src/include/duckdb/execution/index/art/iterator.hpp index 793dcf40b..46a933edc 100644 --- a/src/duckdb/src/include/duckdb/execution/index/art/iterator.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/art/iterator.hpp @@ -11,6 +11,7 @@ #include "duckdb/execution/index/art/art_key.hpp" #include "duckdb/execution/index/art/leaf.hpp" #include "duckdb/execution/index/art/node.hpp" +#include "duckdb/storage/arena_allocator.hpp" namespace duckdb { @@ -43,6 +44,10 @@ class IteratorKey { inline idx_t Size() const { return key_bytes.size(); } + //! Returns a pointer to the key bytes. + inline const_data_ptr_t Data() const { + return const_data_ptr_cast(key_bytes.data()); + } //! Returns true, if key_bytes contains all bytes of key. bool Contains(const ARTKey &key) const; @@ -53,6 +58,71 @@ class IteratorKey { unsafe_vector key_bytes; }; +//===--------------------------------------------------------------------===// +// Scan Output Policies +//===--------------------------------------------------------------------===// + +//! Output policy for scanning row IDs only into a set. +struct RowIdSetOutput { + set &row_ids; + const idx_t capacity; + + RowIdSetOutput(set &row_ids, const idx_t capacity) : row_ids(row_ids), capacity(capacity) { + } + + bool IsFull() const { + D_ASSERT(row_ids.size() >= 0 && row_ids.size() <= capacity); + return row_ids.size() >= capacity; + } + void SetKey(const IteratorKey &, const idx_t) { + // No-op: we don't need keys for row ID output. + } + void Add(const row_t rid) { + row_ids.insert(rid); + } +}; + +//! Output policy for scanning keys and row IDs. +struct KeyRowIdOutput { + ArenaAllocator &arena; + unsafe_vector &keys; + unsafe_vector &row_id_keys; + const idx_t capacity; + idx_t count = 0; + const_data_ptr_t key_data = nullptr; + idx_t key_len = 0; + + KeyRowIdOutput(ArenaAllocator &arena, unsafe_vector &keys, unsafe_vector &row_id_keys, + const idx_t capacity) + : arena(arena), keys(keys), row_id_keys(row_id_keys), capacity(capacity) { + } + + idx_t Count() const { + return count; + } + void Reset() { + count = 0; + arena.Reset(); + } + bool IsFull() const { + D_ASSERT(count >= 0 && count <= capacity); + return count >= capacity; + } + void SetKey(const IteratorKey ¤t_key, const idx_t column_key_len) { + key_data = current_key.Data(); + key_len = column_key_len; + } + void Add(const row_t rid) { + keys[count] = ARTKey::CreateARTKeyFromBytes(arena, key_data, key_len); + row_id_keys[count] = ARTKey::CreateARTKey(arena, rid); + count++; + } +}; + +//! Scanning state. The scanning output policies allow us to pass in a capacity while scanning, so that when the +//! scan fills up the capacity, we can pause the scan state at that location, and resume scanning later. +enum class ARTScanResult : uint8_t { COMPLETED = 0, PAUSED = 1 }; + class Iterator { public: static constexpr uint8_t ROW_ID_SIZE = sizeof(row_t); @@ -63,9 +133,11 @@ class Iterator { IteratorKey current_key; public: - //! Scans the tree, starting at the current top node on the stack, and ending at upper_bound. - //! If upper_bound is the empty ARTKey, than there is no upper bound. - bool Scan(const ARTKey &upper_bound, const idx_t max_count, set &row_ids, const bool equal); + //! Templated scan implementation. Output policy defines how results are emitted. + //! Returns COMPLETED if scan finished, PAUSED if stopped due to output capacity. + template + ARTScanResult Scan(const ARTKey &upper_bound, Output &output, bool equal); + //! Finds the minimum (leaf) of the current subtree. void FindMinimum(const Node &node); //! Finds the lower bound of the ART and adds the nodes to the stack. Returns false, if the lower @@ -93,6 +165,19 @@ class Iterator { //! True, if we entered a nested leaf to retrieve the next node. bool entered_nested_leaf = false; + //! State for resuming a scan after early return due to the Output policy capacity (see note for the ARTScanResult + //! enum). + struct ResumeScanState { + //! For LEAF: cached row IDs and current position. + set cached_row_ids; + set::iterator cached_row_ids_it; + bool has_cached_row_ids = false; + //! For nested leaves: current byte position and whether we've started. + uint8_t nested_byte = 0; + bool nested_started = false; + }; + ResumeScanState resume_state; + private: //! Goes to the next leaf in the ART and sets it as last_leaf, //! returns false if there is no next leaf. diff --git a/src/duckdb/src/include/duckdb/execution/index/art/node.hpp b/src/duckdb/src/include/duckdb/execution/index/art/node.hpp index 3a02c3eec..465eddfab 100644 --- a/src/duckdb/src/include/duckdb/execution/index/art/node.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/art/node.hpp @@ -225,15 +225,6 @@ class Node : public IndexPointer { inline void operator=(const IndexPointer &ptr) { Set(ptr.Get()); } - -private: - template - static void TransformToDeprecatedInternal(ART &art, unsafe_optional_ptr ptr, - TransformToDeprecatedState &state) { - if (ptr) { - NODE::Iterator(*ptr, [&](Node &child) { Node::TransformToDeprecated(art, child, state); }); - } - } }; //! NodeChildren holds the extracted bytes of a node, and their respective children. diff --git a/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp b/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp index b8c77733f..9c3b09455 100644 --- a/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp @@ -25,6 +25,7 @@ class Prefix { static constexpr uint8_t ROW_ID_SIZE = sizeof(row_t); static constexpr uint8_t ROW_ID_COUNT = ROW_ID_SIZE - 1; static constexpr uint8_t DEPRECATED_COUNT = 15; + // The child pointer and the in_memory boolean. static constexpr uint8_t METADATA_SIZE = sizeof(Node) + 1; public: diff --git a/src/duckdb/src/include/duckdb/execution/index/art/prefix_handle.hpp b/src/duckdb/src/include/duckdb/execution/index/art/prefix_handle.hpp index d85a51747..3b5c905c4 100644 --- a/src/duckdb/src/include/duckdb/execution/index/art/prefix_handle.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/art/prefix_handle.hpp @@ -39,7 +39,10 @@ class PrefixHandle { //! Create a new deprecated prefix node and return a handle to it. static PrefixHandle NewDeprecated(FixedSizeAllocator &allocator, Node &node); - static void TransformToDeprecated(ART &art, Node &node, TransformToDeprecatedState &state); + //! Transform prefix chain to deprecated format. + //! nullptr denotes an early out optimization (the prefix has not been loaded from storage, hence we do not need + //! to transform it. Otherwise, we get a pointer to the child node at the end of the prefix chain. + static optional_ptr TransformToDeprecated(ART &art, Node &node, TransformToDeprecatedState &state); private: PrefixHandle TransformToDeprecatedAppend(ART &art, FixedSizeAllocator &allocator, const uint8_t byte); diff --git a/src/duckdb/src/include/duckdb/execution/index/index_type.hpp b/src/duckdb/src/include/duckdb/execution/index/index_type.hpp index 801ad712a..8d0768758 100644 --- a/src/duckdb/src/include/duckdb/execution/index/index_type.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/index_type.hpp @@ -26,8 +26,10 @@ class Expression; class TableIOManager; class AttachedDatabase; struct IndexStorageInfo; +class ClientContext; struct CreateIndexInput { + ClientContext &context; TableIOManager &table_io_manager; AttachedDatabase &db; IndexConstraintType constraint_type; @@ -37,11 +39,11 @@ struct CreateIndexInput { const IndexStorageInfo &storage_info; const case_insensitive_map_t &options; - CreateIndexInput(TableIOManager &table_io_manager, AttachedDatabase &db, IndexConstraintType constraint_type, - const string &name, const vector &column_ids, + CreateIndexInput(ClientContext &context, TableIOManager &table_io_manager, AttachedDatabase &db, + IndexConstraintType constraint_type, const string &name, const vector &column_ids, const vector> &unbound_expressions, const IndexStorageInfo &storage_info, const case_insensitive_map_t &options) - : table_io_manager(table_io_manager), db(db), constraint_type(constraint_type), name(name), + : context(context), table_io_manager(table_io_manager), db(db), constraint_type(constraint_type), name(name), column_ids(column_ids), unbound_expressions(unbound_expressions), storage_info(storage_info), options(options) {}; }; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer.hpp index 7ee7d60a3..1abb1ce03 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer.hpp @@ -72,7 +72,7 @@ class CSVBuffer { return char_ptr_cast(handle.Ptr()); } bool IsUnloaded() const { - return block->IsUnloaded(); + return block->GetMemory().IsUnloaded(); } //! By default, we use CSV_BUFFER_SIZE to allocate each buffer diff --git a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_set.hpp b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_set.hpp index 88345b3cc..56da7a90e 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_set.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_set.hpp @@ -16,6 +16,7 @@ namespace duckdb { struct DBConfig; +struct ConfigurationOption; struct ExtensionOption; //! PhysicalSet represents a SET operation (e.g. SET a = 42) @@ -42,7 +43,8 @@ class PhysicalSet : public PhysicalOperator { static void SetExtensionVariable(ClientContext &context, ExtensionOption &extension_option, const String &name, SetScope scope, const Value &value); - static void SetGenericVariable(ClientContext &context, const String &name, SetScope scope, Value target_value); + static void SetGenericVariable(ClientContext &context, idx_t setting_index, SetScope scope, Value target_value); + static SetScope GetSettingScope(const ConfigurationOption &option, SetScope variable_scope); public: String name; diff --git a/src/duckdb/src/include/duckdb/execution/operator/join/physical_range_join.hpp b/src/duckdb/src/include/duckdb/execution/operator/join/physical_range_join.hpp index 86bf51dc2..85f38ec97 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/join/physical_range_join.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/join/physical_range_join.hpp @@ -154,8 +154,8 @@ class PhysicalRangeJoin : public PhysicalComparisonJoin { public: // Gather the result values and slice the payload columns to those values. static void SliceSortedPayload(DataChunk &chunk, GlobalSortedTable &table, ExternalBlockIteratorState &state, - TupleDataChunkState &chunk_state, const idx_t chunk_idx, const vector &result, - SortedRunScanState &scan_state); + TupleDataChunkState &chunk_state, const idx_t chunk_idx, + const unsafe_vector &result, SortedRunScanState &scan_state); // 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); diff --git a/src/duckdb/src/include/duckdb/execution/physical_table_scan_enum.hpp b/src/duckdb/src/include/duckdb/execution/physical_table_scan_enum.hpp index 7fddde85d..0d275e2b3 100644 --- a/src/duckdb/src/include/duckdb/execution/physical_table_scan_enum.hpp +++ b/src/duckdb/src/include/duckdb/execution/physical_table_scan_enum.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/common/enums/physical_table_scan_enum.hpp +// duckdb/execution/physical_table_scan_enum.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/function/cast/default_casts.hpp b/src/duckdb/src/include/duckdb/function/cast/default_casts.hpp index 107b482b7..cab0e28f7 100644 --- a/src/duckdb/src/include/duckdb/function/cast/default_casts.hpp +++ b/src/duckdb/src/include/duckdb/function/cast/default_casts.hpp @@ -171,6 +171,7 @@ struct DefaultCasts { static BoundCastInfo VariantCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target); static BoundCastInfo UUIDCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target); static BoundCastInfo GeoCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target); + static BoundCastInfo TypeCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target); static BoundCastInfo BignumCastSwitch(BindCastInput &input, const LogicalType &source, const LogicalType &target); static BoundCastInfo ImplicitToUnionCast(BindCastInput &input, const LogicalType &source, const LogicalType &target); diff --git a/src/duckdb/src/include/duckdb/function/cast/variant/primitive_to_variant.hpp b/src/duckdb/src/include/duckdb/function/cast/variant/primitive_to_variant.hpp index 9aa105bd3..250daef4a 100644 --- a/src/duckdb/src/include/duckdb/function/cast/variant/primitive_to_variant.hpp +++ b/src/duckdb/src/include/duckdb/function/cast/variant/primitive_to_variant.hpp @@ -392,6 +392,8 @@ bool ConvertPrimitiveToVariant(ToVariantSourceData &source, ToVariantGlobalResul case LogicalTypeId::BIT: return ConvertPrimitiveTemplated( source, result, count, selvec, values_index_selvec, empty_payload, is_root); + case LogicalTypeId::TYPE: + throw NotImplementedException("Cannot convert TYPE to VARIANT"); default: throw NotImplementedException("Invalid LogicalType (%s) for ConvertToVariant", EnumUtil::ToString(logical_type)); diff --git a/src/duckdb/src/include/duckdb/function/scalar/variant_utils.hpp b/src/duckdb/src/include/duckdb/function/scalar/variant_utils.hpp index 1c20b19c0..78eb7bd36 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/variant_utils.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/variant_utils.hpp @@ -16,6 +16,20 @@ namespace duckdb { +struct VariantExtractBindData : public FunctionData { +public: + explicit VariantExtractBindData(const string &str); + explicit VariantExtractBindData(uint32_t index); + VariantExtractBindData(const VariantExtractBindData &other) = default; + +public: + unique_ptr Copy() const override; + bool Equals(const FunctionData &other) const override; + +public: + VariantPathComponent component; +}; + struct VariantNestedDataCollectionResult { public: VariantNestedDataCollectionResult() : success(true) { @@ -73,10 +87,11 @@ struct VariantUtils { DUCKDB_API static void FindChildValues(const UnifiedVariantVectorData &variant, const VariantPathComponent &component, optional_ptr sel, SelectionVector &res, - ValidityMask &res_validity, VariantNestedData *nested_data, idx_t count); + ValidityMask &res_validity, const VariantNestedData *nested_data, + const ValidityMask &validity, idx_t count); DUCKDB_API static VariantNestedDataCollectionResult CollectNestedData(const UnifiedVariantVectorData &variant, VariantLogicalType expected_type, - const SelectionVector &sel, idx_t count, optional_idx row, idx_t offset, + const SelectionVector &value_index_sel, idx_t count, optional_idx row, idx_t offset, VariantNestedData *child_data, ValidityMask &validity); DUCKDB_API static vector ValueIsNull(const UnifiedVariantVectorData &variant, const SelectionVector &sel, idx_t count, optional_idx row); @@ -85,6 +100,8 @@ struct VariantUtils { DUCKDB_API static bool Verify(Vector &variant, const SelectionVector &sel_p, idx_t count); DUCKDB_API static void FinalizeVariantKeys(Vector &variant, OrderedOwningStringMap &dictionary, SelectionVector &sel, idx_t sel_size); + DUCKDB_API static void VariantExtract(Vector &input, const vector &components, Vector &result, + idx_t count); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/table/arrow.hpp b/src/duckdb/src/include/duckdb/function/table/arrow.hpp index c758f2ed5..75ce9b37a 100644 --- a/src/duckdb/src/include/duckdb/function/table/arrow.hpp +++ b/src/duckdb/src/include/duckdb/function/table/arrow.hpp @@ -233,7 +233,7 @@ struct ArrowTableFunction { //! Scan Function static void ArrowScanFunction(ClientContext &context, TableFunctionInput &data, DataChunk &output); - static void PopulateArrowTableSchema(DBConfig &config, ArrowTableSchema &arrow_table, + static void PopulateArrowTableSchema(ClientContext &context, ArrowTableSchema &arrow_table, const ArrowSchema &arrow_schema); protected: diff --git a/src/duckdb/src/include/duckdb/function/table/arrow/arrow_duck_schema.hpp b/src/duckdb/src/include/duckdb/function/table/arrow/arrow_duck_schema.hpp index 44472ea63..a94b4e6ff 100644 --- a/src/duckdb/src/include/duckdb/function/table/arrow/arrow_duck_schema.hpp +++ b/src/duckdb/src/include/duckdb/function/table/arrow/arrow_duck_schema.hpp @@ -85,14 +85,14 @@ class ArrowType { void ThrowIfInvalid() const; static unique_ptr GetTypeFromFormat(string &format); - static unique_ptr GetTypeFromFormat(DBConfig &config, ArrowSchema &schema, string &format); + static unique_ptr GetTypeFromFormat(ClientContext &context, ArrowSchema &schema, string &format); - static unique_ptr GetTypeFromSchema(DBConfig &config, ArrowSchema &schema); + static unique_ptr GetTypeFromSchema(ClientContext &context, ArrowSchema &schema); - static unique_ptr CreateListType(DBConfig &config, ArrowSchema &child, ArrowVariableSizeType size_type, - bool view); + static unique_ptr CreateListType(ClientContext &context, ArrowSchema &child, + ArrowVariableSizeType size_type, bool view); - static unique_ptr GetArrowLogicalType(DBConfig &config, ArrowSchema &schema); + static unique_ptr GetArrowLogicalType(ClientContext &context, ArrowSchema &schema); bool HasExtension() const; diff --git a/src/duckdb/src/include/duckdb/function/table/system_functions.hpp b/src/duckdb/src/include/duckdb/function/table/system_functions.hpp index 5944f8cff..b61a407ce 100644 --- a/src/duckdb/src/include/duckdb/function/table/system_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/table/system_functions.hpp @@ -63,6 +63,10 @@ struct DuckDBConstraintsFun { static void RegisterFunction(BuiltinFunctions &set); }; +struct DuckDBCoordinateSystemsFun { + static void RegisterFunction(BuiltinFunctions &set); +}; + struct DuckDBSecretsFun { static void RegisterFunction(BuiltinFunctions &set); }; diff --git a/src/duckdb/src/include/duckdb/function/table_function.hpp b/src/duckdb/src/include/duckdb/function/table_function.hpp index 2869cdff7..2ac2cf73d 100644 --- a/src/duckdb/src/include/duckdb/function/table_function.hpp +++ b/src/duckdb/src/include/duckdb/function/table_function.hpp @@ -36,9 +36,9 @@ class SampleOptions; struct MultiFileReader; struct OperatorPartitionData; struct OperatorPartitionInfo; -enum class OrderByColumnType; -enum class RowGroupOrderType; -enum class OrderByStatistics; +enum class OrderByColumnType : uint8_t; +enum class OrderType : uint8_t; +enum class OrderByStatistics : uint8_t; struct TableFunctionInfo { DUCKDB_API virtual ~TableFunctionInfo(); diff --git a/src/duckdb/src/include/duckdb/function/variant/variant_shredding.hpp b/src/duckdb/src/include/duckdb/function/variant/variant_shredding.hpp index b30438b84..ecd8a463e 100644 --- a/src/duckdb/src/include/duckdb/function/variant/variant_shredding.hpp +++ b/src/duckdb/src/include/duckdb/function/variant/variant_shredding.hpp @@ -75,9 +75,14 @@ struct VariantShredding { optional_ptr value_index_sel, optional_ptr result_sel, idx_t count) = 0; +protected: + idx_t typed_value_index = VariantStats::TYPED_VALUE_INDEX; + idx_t untyped_value_index = VariantStats::UNTYPED_VALUE_INDEX; + protected: void WriteTypedValues(UnifiedVariantVectorData &variant, Vector &result, const SelectionVector &sel, const SelectionVector &value_index_sel, const SelectionVector &result_sel, idx_t count); + virtual void WriteMissingField(Vector &vector, idx_t index); private: void WriteTypedObjectValues(UnifiedVariantVectorData &variant, Vector &result, const SelectionVector &sel, diff --git a/src/duckdb/src/include/duckdb/function/variant/variant_value_convert.hpp b/src/duckdb/src/include/duckdb/function/variant/variant_value_convert.hpp index 3b83418fa..5565c472b 100644 --- a/src/duckdb/src/include/duckdb/function/variant/variant_value_convert.hpp +++ b/src/duckdb/src/include/duckdb/function/variant/variant_value_convert.hpp @@ -103,7 +103,16 @@ struct ValueConverter { static Value VisitArray(const UnifiedVariantVectorData &variant, idx_t row, const VariantNestedData &nested_data) { auto array_items = VariantVisitor::VisitArrayItems(variant, row, nested_data); - return Value::LIST(LogicalType::VARIANT(), std::move(array_items)); + if (array_items.empty()) { + return Value::LIST(LogicalType::VARIANT(), std::move(array_items)); + } + auto &child_type = array_items[0].type(); + for (idx_t i = 1; i < array_items.size(); i++) { + if (child_type != array_items[i].type()) { + return Value::LIST(LogicalType::VARIANT(), std::move(array_items)); + } + } + return Value::LIST(child_type, std::move(array_items)); } static Value VisitObject(const UnifiedVariantVectorData &variant, idx_t row, const VariantNestedData &nested_data) { diff --git a/src/duckdb/src/include/duckdb/function/window/window_value_function.hpp b/src/duckdb/src/include/duckdb/function/window/window_value_function.hpp index 4504cfc30..04a0fae39 100644 --- a/src/duckdb/src/include/duckdb/function/window/window_value_function.hpp +++ b/src/duckdb/src/include/duckdb/function/window/window_value_function.hpp @@ -79,7 +79,7 @@ class WindowNthValueExecutor : public WindowValueExecutor { class WindowFillExecutor : public WindowValueExecutor { public: - WindowFillExecutor(BoundWindowExpression &wexpr, WindowSharedExpressions &shared); + WindowFillExecutor(BoundWindowExpression &wexpr, ClientContext &client, WindowSharedExpressions &shared); //! Never ignore nulls (that's the point!) bool IgnoreNulls() const override { diff --git a/src/duckdb/src/include/duckdb/logging/log_manager.hpp b/src/duckdb/src/include/duckdb/logging/log_manager.hpp index 54f623a55..d35a21ad3 100644 --- a/src/duckdb/src/include/duckdb/logging/log_manager.hpp +++ b/src/duckdb/src/include/duckdb/logging/log_manager.hpp @@ -85,12 +85,13 @@ class LogManager { void SetConfigInternal(LogConfig config); +protected: mutex lock; LogConfig config; shared_ptr global_logger; - shared_ptr log_storage; + DatabaseInstance &db_instance; idx_t next_registered_logging_context_index = 0; diff --git a/src/duckdb/src/include/duckdb/logging/logger.hpp b/src/duckdb/src/include/duckdb/logging/logger.hpp index 0c132fe2c..01655bde1 100644 --- a/src/duckdb/src/include/duckdb/logging/logger.hpp +++ b/src/duckdb/src/include/duckdb/logging/logger.hpp @@ -62,7 +62,7 @@ class Logger { // Main Logging interface. In most cases the macros above should be used instead of calling these directly DUCKDB_API virtual bool ShouldLog(const char *log_type, LogLevel log_level) = 0; - DUCKDB_API virtual void WriteLog(const char *log_type, LogLevel log_level, const char *message) = 0; + DUCKDB_API void WriteLog(const char *log_type, LogLevel log_level, const char *message); // Some more string types for easy logging DUCKDB_API void WriteLog(const char *log_type, LogLevel log_level, const string &message); @@ -101,6 +101,9 @@ class Logger { } DUCKDB_API virtual const LogConfig &GetConfig() const = 0; +protected: + virtual void WriteLogInternal(const char *log_type, LogLevel log_level, const char *message) = 0; + protected: LogManager &manager; }; @@ -113,7 +116,7 @@ class ThreadSafeLogger : public Logger { // Main Logger API bool ShouldLog(const char *log_type, LogLevel log_level) override; - void WriteLog(const char *log_type, LogLevel log_level, const char *message) override; + void WriteLogInternal(const char *log_type, LogLevel log_level, const char *message) override; void Flush() override; bool IsThreadSafe() override { @@ -138,7 +141,7 @@ class ThreadLocalLogger : public Logger { // Main Logger API bool ShouldLog(const char *log_type, LogLevel log_level) override; - void WriteLog(const char *log_type, LogLevel log_level, const char *message) override; + void WriteLogInternal(const char *log_type, LogLevel log_level, const char *message) override; void Flush() override; bool IsThreadSafe() override { @@ -161,7 +164,7 @@ class MutableLogger : public Logger { // Main Logger API bool ShouldLog(const char *log_type, LogLevel log_level) override; - void WriteLog(const char *log_type, LogLevel log_level, const char *message) override; + void WriteLogInternal(const char *log_type, LogLevel log_level, const char *message) override; void Flush() override; bool IsThreadSafe() override { @@ -194,7 +197,7 @@ class NopLogger : public Logger { bool ShouldLog(const char *log_type, LogLevel log_level) override { return false; } - void WriteLog(const char *log_type, LogLevel log_level, const char *message) override {}; + void WriteLogInternal(const char *log_type, LogLevel log_level, const char *message) override {}; void Flush() override { } bool IsThreadSafe() override { diff --git a/src/duckdb/src/include/duckdb/logging/logging.hpp b/src/duckdb/src/include/duckdb/logging/logging.hpp index 11d0760c7..8c74d38fa 100644 --- a/src/duckdb/src/include/duckdb/logging/logging.hpp +++ b/src/duckdb/src/include/duckdb/logging/logging.hpp @@ -41,12 +41,6 @@ struct LogConfig { LogConfig(); - DUCKDB_API static LogConfig Create(bool enabled, LogLevel level); - DUCKDB_API static LogConfig CreateFromEnabled(bool enabled, LogLevel level, - unordered_set &enabled_log_types); - DUCKDB_API static LogConfig CreateFromDisabled(bool enabled, LogLevel level, - unordered_set &disabled_log_types); - DUCKDB_API bool IsConsistent() const; bool enabled; diff --git a/src/duckdb/src/include/duckdb/main/appender.hpp b/src/duckdb/src/include/duckdb/main/appender.hpp index b637717f8..f1b6c091f 100644 --- a/src/duckdb/src/include/duckdb/main/appender.hpp +++ b/src/duckdb/src/include/duckdb/main/appender.hpp @@ -14,11 +14,12 @@ namespace duckdb { -class ColumnDataCollection; class ClientContext; +class ColumnDataCollection; +class Connection; class DuckDB; +class SQLStatement; class TableCatalogEntry; -class Connection; enum class AppenderType : uint8_t { LOGICAL, // Cast input -> LogicalType @@ -31,6 +32,14 @@ class BaseAppender { //! The amount of tuples that are gathered in the column data collection before flushing. static constexpr const idx_t DEFAULT_FLUSH_COUNT = STANDARD_VECTOR_SIZE * 100ULL; +public: + //! Returns a table reference to the appended data. + static unique_ptr GetColumnDataTableRef(ColumnDataCollection &collection, const string &table_name, + const vector &expected_names); + //! Parses the statement to append data. + static unique_ptr ParseStatement(unique_ptr table_ref, const string &query, + const string &table_name); + protected: //! The allocator for the column data collection. Allocator &allocator; @@ -148,6 +157,11 @@ class Appender : public BaseAppender { void AppendDefault(DataChunk &chunk, idx_t col, idx_t row) override; void AddColumn(const string &name) override; void ClearColumns() override; + //! Get the expected names based on the active columns. + vector GetExpectedNames(); + //! Construct a query that appends data from, typically, a column data collection. + static string ConstructQuery(TableDescription &description_p, const string &table_name, + const vector &expected_names); private: //! A shared pointer to the context of this appender. @@ -176,11 +190,11 @@ class QueryAppender : public BaseAppender { private: //! A shared pointer to the context of this appender. weak_ptr context; - //! The query to run + //! The query to run. string query; - //! The column names of the to-be-appended data, or "col1, col2, ..." if empty + //! The column names of the to-be-appended data, or "col1, col2, ...", if empty. vector names; - //! The table name that we can reference in the query, or "appended_data" if empty + //! The table name that we can reference in the query, or "appended_data", if empty. string table_name; protected: diff --git a/src/duckdb/src/include/duckdb/main/attached_database.hpp b/src/duckdb/src/include/duckdb/main/attached_database.hpp index 7a0d95a1b..da561c982 100644 --- a/src/duckdb/src/include/duckdb/main/attached_database.hpp +++ b/src/duckdb/src/include/duckdb/main/attached_database.hpp @@ -154,7 +154,7 @@ class AttachedDatabase : public CatalogEntry, public enable_shared_from_this close_lock; unordered_map attach_options; private: diff --git a/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp b/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp index b32dd04df..9be892ef5 100644 --- a/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp +++ b/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp @@ -644,6 +644,7 @@ typedef struct { // New string functions that are added char *(*duckdb_value_to_string)(duckdb_value value); + duckdb_error_data (*duckdb_valid_utf8_check)(const char *str, idx_t len); // New functions around the table description idx_t (*duckdb_table_description_get_column_count)(duckdb_table_description table_description); @@ -671,7 +672,8 @@ typedef struct { sel_t *(*duckdb_selection_vector_get_data_ptr)(duckdb_selection_vector sel); void (*duckdb_vector_copy_sel)(duckdb_vector src, duckdb_vector dst, duckdb_selection_vector sel, idx_t src_count, idx_t src_offset, idx_t dst_offset); - duckdb_error_data (*duckdb_vector_safe_assign_string_element)(duckdb_vector vector, idx_t index, const char *str); + void (*duckdb_unsafe_vector_assign_string_element_len)(duckdb_vector vector, idx_t index, const char *str, + idx_t str_len); } duckdb_ext_api_v1; //===--------------------------------------------------------------------===// @@ -1206,6 +1208,7 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_scalar_function_init_get_bind_data = duckdb_scalar_function_init_get_bind_data; result.duckdb_scalar_function_init_get_extra_info = duckdb_scalar_function_init_get_extra_info; result.duckdb_value_to_string = duckdb_value_to_string; + result.duckdb_valid_utf8_check = duckdb_valid_utf8_check; result.duckdb_table_description_get_column_count = duckdb_table_description_get_column_count; result.duckdb_table_description_get_column_type = duckdb_table_description_get_column_type; result.duckdb_table_function_get_client_context = duckdb_table_function_get_client_context; @@ -1222,7 +1225,7 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_destroy_selection_vector = duckdb_destroy_selection_vector; result.duckdb_selection_vector_get_data_ptr = duckdb_selection_vector_get_data_ptr; result.duckdb_vector_copy_sel = duckdb_vector_copy_sel; - result.duckdb_vector_safe_assign_string_element = duckdb_vector_safe_assign_string_element; + result.duckdb_unsafe_vector_assign_string_element_len = duckdb_unsafe_vector_assign_string_element_len; return result; } diff --git a/src/duckdb/src/include/duckdb/main/client_config.hpp b/src/duckdb/src/include/duckdb/main/client_config.hpp index e2b5c6926..40980b8a0 100644 --- a/src/duckdb/src/include/duckdb/main/client_config.hpp +++ b/src/duckdb/src/include/duckdb/main/client_config.hpp @@ -17,6 +17,7 @@ #include "duckdb/main/profiling_info.hpp" #include "duckdb/parser/expression/lambda_expression.hpp" #include "duckdb/main/query_profiler.hpp" +#include "duckdb/main/user_settings.hpp" namespace duckdb { @@ -27,8 +28,6 @@ class PreparedStatementData; typedef std::function get_result_collector_t; struct ClientConfig { - //! The home directory used by the system (if any) - string home_directory; //! If the query profiler is enabled or not. bool enable_profiler = false; //! If detailed query profiling is enabled @@ -57,9 +56,6 @@ struct ClientConfig { //! The wait time before showing the progress bar int wait_time = 2000; - //! The maximum expression depth limit in the parser - idx_t max_expression_depth = 1000; - //! Whether or not aggressive query verification is enabled bool query_verification_enabled = false; //! Whether or not verification of external operators is enabled, used for testing @@ -88,21 +84,12 @@ struct ClientConfig { //! Callback to create a progress bar display progress_bar_display_create_func_t display_create_func = nullptr; - //! The explain output type used when none is specified (default: PHYSICAL_ONLY) - ExplainOutputType explain_output_type = ExplainOutputType::PHYSICAL_ONLY; - - //! If DEFAULT or ENABLE_SINGLE_ARROW, it is possible to use the deprecated single arrow operator (->) for lambda - //! functions. Otherwise, DISABLE_SINGLE_ARROW. - LambdaSyntax lambda_syntax = LambdaSyntax::DEFAULT; //! The profiling coverage. SELECT is the default behavior, and ALL emits profiling information for all operator //! types. ProfilingCoverage profiling_coverage = ProfilingCoverage::SELECT; - //! Output error messages as structured JSON instead of as a raw string - bool errors_as_json = false; - //! Generic options - case_insensitive_map_t set_variables; + LocalUserSettings user_settings; //! Variables set by the user case_insensitive_map_t user_variables; @@ -127,16 +114,6 @@ struct ClientConfig { bool GetUserVariable(const string &name, Value &result); void ResetUserVariable(const String &name); - template - static typename OP::RETURN_TYPE GetSetting(const ClientContext &context) { - return OP::GetSetting(context).template GetValue(); - } - - template - static Value GetSettingValue(const ClientContext &context) { - return OP::GetSetting(context); - } - public: void SetDefaultStreamingBufferSize(); }; diff --git a/src/duckdb/src/include/duckdb/main/client_context.hpp b/src/duckdb/src/include/duckdb/main/client_context.hpp index 02edee9ca..e73e60bca 100644 --- a/src/duckdb/src/include/duckdb/main/client_context.hpp +++ b/src/duckdb/src/include/duckdb/main/client_context.hpp @@ -136,12 +136,10 @@ class ClientContext : public enable_shared_from_this { const string &table_name); //! Get the table info of a specific table, or nullptr if it cannot be found. Uses INVALID_CATALOG. DUCKDB_API unique_ptr TableInfo(const string &schema_name, const string &table_name); - //! Execute a query with the given collection "attached" to the query using a CTE - DUCKDB_API void Append(ColumnDataCollection &collection, const string &query, const vector &column_names, - const string &collection_name); - //! Appends a DataChunk and its default columns to the specified table. - DUCKDB_API void Append(TableDescription &description, ColumnDataCollection &collection, - optional_ptr> column_ids = nullptr); + //! Executes a query with the given collection "attached" to the query using a CTE. + DUCKDB_API void Append(unique_ptr stmt); + //! Appends a ColumnDataCollection to the described table. + DUCKDB_API void Append(TableDescription &description, ColumnDataCollection &collection); //! Try to bind a relation in the current client context; either throws an exception or fills the result_columns //! list with the set of returned columns @@ -200,6 +198,8 @@ class ClientContext : public enable_shared_from_this { //! Equivalent to CURRENT_SETTING(key) SQL function. DUCKDB_API SettingLookupResult TryGetCurrentSetting(const string &key, Value &result) const; + //! Returns the value of the current setting set by the user - if the user has set it. + DUCKDB_API SettingLookupResult TryGetCurrentUserSetting(idx_t setting_index, Value &result) const; //! Returns the parser options for this client context DUCKDB_API ParserOptions GetParserOptions() const; @@ -231,6 +231,8 @@ class ClientContext : public enable_shared_from_this { //! Process an error for display to the user DUCKDB_API void ProcessError(ErrorData &error, const string &query) const; + DUCKDB_API LogicalType ParseLogicalType(const string &type); + private: //! Parse statements and resolve pragmas from a query vector> ParseStatements(ClientContextLock &lock, const string &query); @@ -309,8 +311,6 @@ class ClientContext : public enable_shared_from_this { unique_ptr statement, PendingQueryParameters parameters); - SettingLookupResult TryGetCurrentSettingInternal(const string &key, Value &result) const; - private: //! Lock on using the ClientContext in parallel mutex context_lock; diff --git a/src/duckdb/src/include/duckdb/main/client_data.hpp b/src/duckdb/src/include/duckdb/main/client_data.hpp index 7e901c498..a2068b68e 100644 --- a/src/duckdb/src/include/duckdb/main/client_data.hpp +++ b/src/duckdb/src/include/duckdb/main/client_data.hpp @@ -44,8 +44,6 @@ struct ClientData { //! The catalog search path. unique_ptr catalog_search_path; - //! The file search path. - string file_search_path; //! The file opener of the client context. unique_ptr file_opener; diff --git a/src/duckdb/src/include/duckdb/main/config.hpp b/src/duckdb/src/include/duckdb/main/config.hpp index 757d67c89..1d3766a4c 100644 --- a/src/duckdb/src/include/duckdb/main/config.hpp +++ b/src/duckdb/src/include/duckdb/main/config.hpp @@ -9,12 +9,11 @@ #pragma once #include "duckdb/common/arrow/arrow_type_extension.hpp" - +#include "duckdb/storage/storage_info.hpp" #include "duckdb/common/allocator.hpp" #include "duckdb/common/case_insensitive_map.hpp" #include "duckdb/common/cgroups.hpp" #include "duckdb/common/common.hpp" -#include "duckdb/common/encryption_state.hpp" #include "duckdb/common/enums/access_mode.hpp" #include "duckdb/common/enums/cache_validation_mode.hpp" #include "duckdb/common/enums/thread_pin_mode.hpp" @@ -30,14 +29,13 @@ #include "duckdb/execution/index/index_type_set.hpp" #include "duckdb/function/cast/default_casts.hpp" #include "duckdb/function/replacement_scan.hpp" -#include "duckdb/optimizer/optimizer_extension.hpp" -#include "duckdb/parser/parsed_data/create_info.hpp" -#include "duckdb/parser/parser_extension.hpp" -#include "duckdb/planner/operator_extension.hpp" #include "duckdb/storage/compression/bitpacking.hpp" #include "duckdb/function/encoding_function.hpp" #include "duckdb/main/setting_info.hpp" #include "duckdb/logging/log_manager.hpp" +#include "duckdb/main/user_settings.hpp" +#include "duckdb/parser/parsed_data/create_info.hpp" +#include "duckdb/common/types/type_manager.hpp" namespace duckdb { @@ -58,6 +56,8 @@ class CompressionInfo; class EncryptionUtil; class HTTPUtil; class DatabaseFilePathManager; +class ExtensionCallbackManager; +class TypeManager; struct CompressionFunctionSet; struct DatabaseCacheEntry; @@ -87,6 +87,9 @@ class SerializationCompatibility { SerializationCompatibility() = default; }; +//! NOTE: DBConfigOptions is mostly deprecated. +//! If you want to add a setting that can be set by the user, add it as a generic setting to `settings.json`. +//! See e.g. "http_proxy" (HTTPProxySetting) as an example struct DBConfigOptions { //! Database file path. May be empty for in-memory mode string database_path; @@ -100,33 +103,12 @@ struct DBConfigOptions { bool use_direct_io = false; //! Whether extensions should be loaded on start-up bool load_extensions = true; -#ifdef DUCKDB_EXTENSION_AUTOLOAD_DEFAULT - //! Whether known extensions are allowed to be automatically loaded when a query depends on them - bool autoload_known_extensions = DUCKDB_EXTENSION_AUTOLOAD_DEFAULT; -#else - bool autoload_known_extensions = false; -#endif -#ifdef DUCKDB_EXTENSION_AUTOINSTALL_DEFAULT - //! Whether known extensions are allowed to be automatically installed when a query depends on them - bool autoinstall_known_extensions = DUCKDB_EXTENSION_AUTOINSTALL_DEFAULT; -#else - bool autoinstall_known_extensions = false; -#endif - //! Setting for the parser override registered by extensions. Allowed options: "default, "fallback", "strict" - string allow_parser_override_extension = "default"; - //! Override for the default extension repository - string custom_extension_repo = ""; - //! Override for the default autoload extension repository - string autoinstall_extension_repo = ""; //! The maximum memory used by the database system (in bytes). Default: 80% of System available memory idx_t maximum_memory = DConstants::INVALID_INDEX; //! The maximum size of the 'temp_directory' folder when set (in bytes). Default: 90% of available disk space. idx_t maximum_swap_space = DConstants::INVALID_INDEX; //! The maximum amount of CPU threads used by the database system. Default: all available. idx_t maximum_threads = DConstants::INVALID_INDEX; - //! The number of external threads that work on DuckDB tasks. Default: 1. - //! Must be smaller or equal to maximum_threads. - idx_t external_threads = 1; //! Whether or not to create and use a temporary directory to store intermediates that do not fit in memory bool use_temporary_directory = true; //! Directory to store temporary structures that do not fit in memory @@ -136,20 +118,6 @@ struct DBConfigOptions { bool trim_free_blocks = false; //! Record timestamps of buffer manager unpin() events. Usable by custom eviction policies. bool buffer_manager_track_eviction_timestamps = false; - //! Whether or not to allow printing unredacted secrets - bool allow_unredacted_secrets = false; - //! Disables invalidating the database instance when encountering a fatal error. - bool disable_database_invalidation = false; - //! enable COPY and related commands - bool enable_external_access = true; - //! Whether or not the global http metadata cache is used - bool http_metadata_cache_enable = false; - //! HTTP Proxy config as 'hostname:port' - string http_proxy; - //! HTTP Proxy username for basic auth - string http_proxy_username; - //! HTTP Proxy password for basic auth - string http_proxy_password; //! Force checkpoint when CHECKPOINT is called or on shutdown, even if no changes have been made bool force_checkpoint = false; //! Run a checkpoint on successful shutdown and delete the WAL, to leave only a single database file behind @@ -159,56 +127,32 @@ struct DBConfigOptions { //! Initialize the database with the standard set of DuckDB functions //! You should probably not touch this unless you know what you are doing bool initialize_default_database = true; + //! Enable mbedtls explicitly (overrides OpenSSL if available) + bool force_mbedtls = false; //! The set of disabled optimizers (default empty) set disabled_optimizers; - //! The average string length required to use ZSTD compression. - uint64_t zstd_min_string_length = 4096; - //! Force a specific compression method to be used when checkpointing (if available) - CompressionType force_compression = CompressionType::COMPRESSION_AUTO; - //! Force a specific bitpacking mode to be used when using the bitpacking compression method - BitpackingMode force_bitpacking_mode = BitpackingMode::AUTO; //! Force a specific schema for VARIANT shredding LogicalType force_variant_shredding = LogicalType::INVALID; - //! Minimum size of a rowgroup to enable VARIANT shredding, -1 to disable - int64_t variant_minimum_shredding_size = 30000; - //! Database configuration variables as controlled by SET - case_insensitive_map_t set_variables; //! Database configuration variable default values; case_insensitive_map_t set_variable_defaults; - //! Directory to store extension binaries in - string extension_directory; //! Additional directories to store extension binaries in vector extension_directories; - //! Whether unsigned extensions should be loaded - bool allow_unsigned_extensions = false; - //! Whether community extensions should be loaded - bool allow_community_extensions = true; //! Debug setting - how to initialize blocks in the storage layer when allocating DebugInitialize debug_initialize = DebugInitialize::NO_INITIALIZE; //! The set of user-provided options case_insensitive_map_t user_options; //! The set of unrecognized (other) options case_insensitive_map_t unrecognized_options; - //! Whether or not the configuration settings can be altered - bool lock_configuration = false; //! Whether to print bindings when printing the plan (debug mode only) static bool debug_print_bindings; // NOLINT: debug setting //! The peak allocation threshold at which to flush the allocator after completing a task (1 << 27, ~128MB) idx_t allocator_flush_threshold = 134217728ULL; //! If bulk deallocation larger than this occurs, flush outstanding allocations (1 << 30, ~1GB) idx_t allocator_bulk_deallocation_flush_threshold = 536870912ULL; - //! Whether the allocator background thread is enabled - bool allocator_background_threads = false; - //! DuckDB API surface - string duckdb_api; //! Metadata from DuckDB callers string custom_user_agent; - //! Encrypt the temp files - bool temp_file_encryption = false; - //! The default block allocation size for new duckdb database files (new as-in, they do not yet exist). - idx_t default_block_alloc_size = DEFAULT_BLOCK_ALLOC_SIZE; //! The default block header size for new duckdb database files. - idx_t default_block_header_size = DUCKDB_BLOCK_HEADER_STORAGE_SIZE; + idx_t default_block_header_size = DEFAULT_BLOCK_HEADER_STORAGE_SIZE; //! Whether or not to abort if a serialization exception is thrown during WAL playback (when reading truncated WAL) bool abort_on_wal_failure = false; //! Paths that are explicitly allowed, even if enable_external_access is false @@ -217,18 +161,6 @@ struct DBConfigOptions { set allowed_directories; //! The log configuration LogConfig log_config = LogConfig(); - //! Whether to enable external file caching using CachingFileSystem - bool enable_external_file_cache = true; - //! Cache validation mode, by default all cache entries are validated. - CacheValidationMode validate_external_file_cache = CacheValidationMode::VALIDATE_ALL; - //! Partially process tasks before rescheduling - allows for more scheduler fairness between separate queries -#ifdef DUCKDB_ALTERNATIVE_VERIFY - bool scheduler_process_partial = true; -#else - bool scheduler_process_partial = false; -#endif - //! Whether to pin threads to cores (linux only, default AUTOMATIC: on when there are more than 64 cores) - ThreadPinMode pin_threads = ThreadPinMode::AUTO; //! Physical memory that the block allocator is allowed to use (this memory is never freed and cannot be reduced) idx_t block_allocator_size = 0; @@ -245,12 +177,9 @@ struct DBConfig { DUCKDB_API DBConfig(const case_insensitive_map_t &config_dict, bool read_only); DUCKDB_API ~DBConfig(); - mutable mutex config_lock; //! Replacement table scans are automatically attempted when a table name cannot be found in the schema vector replacement_scans; - //! Extra parameters that can be SET for loaded extensions - case_insensitive_map_t extension_parameters; //! The FileSystem to use, can be overwritten to allow for injecting custom file systems for testing purposes (e.g. //! RamFS or something similar) unique_ptr file_system; @@ -262,25 +191,15 @@ struct DBConfig { unique_ptr block_allocator; //! Database configuration options DBConfigOptions options; - //! Extensions made to the parser - vector parser_extensions; - //! Extensions made to the optimizer - vector optimizer_extensions; //! Error manager unique_ptr error_manager; //! A reference to the (shared) default allocator (Allocator::DefaultAllocator) shared_ptr default_allocator; - //! Extensions made to binder - vector> operator_extensions; - //! Extensions made to storage - case_insensitive_map_t> storage_extensions; //! A buffer pool can be shared across multiple databases (if desired). shared_ptr buffer_pool; //! Provide a custom buffer manager implementation (if desired). shared_ptr buffer_manager; - //! Set of callbacks that can be installed by extensions - vector> extension_callbacks; - //! Encryption Util for OpenSSL + //! Encryption Util for OpenSSL and MbedTLS shared_ptr encryption_util; //! HTTP Request utility functions shared_ptr http_util; @@ -288,6 +207,8 @@ struct DBConfig { shared_ptr db_cache_entry; //! Reference to the database file path manager shared_ptr path_manager; + //! Database configuration variables as controlled by SET + GlobalUserSettings user_settings; public: DUCKDB_API static DBConfig &GetConfig(ClientContext &context); @@ -305,7 +226,9 @@ struct DBConfig { DUCKDB_API void AddExtensionOption(const string &name, string description, LogicalType parameter, const Value &default_value = Value(), set_option_callback_t function = nullptr, SetScope default_scope = SetScope::SESSION); - DUCKDB_API bool HasExtensionOption(const string &name); + DUCKDB_API bool HasExtensionOption(const string &name) const; + DUCKDB_API case_insensitive_map_t GetExtensionSettings() const; + DUCKDB_API bool TryGetExtensionOption(const String &name, ExtensionOption &result) const; //! Fetch an option by index. Returns a pointer to the option, or nullptr if out of range DUCKDB_API static optional_ptr GetOptionByIndex(idx_t index); //! Fetcha n alias by index, or nullptr if out of range @@ -314,12 +237,15 @@ struct DBConfig { DUCKDB_API static optional_ptr GetOptionByName(const String &name); DUCKDB_API void SetOption(const ConfigurationOption &option, const Value &value); DUCKDB_API void SetOption(optional_ptr db, const ConfigurationOption &option, const Value &value); + DUCKDB_API void SetOption(const string &name, Value value); + DUCKDB_API void SetOption(idx_t setting_index, Value value); DUCKDB_API void SetOptionByName(const string &name, const Value &value); DUCKDB_API void SetOptionsByName(const case_insensitive_map_t &values); DUCKDB_API void ResetOption(optional_ptr db, const ConfigurationOption &option); - DUCKDB_API void SetOption(const String &name, Value value); - DUCKDB_API void ResetOption(const String &name); - DUCKDB_API void ResetGenericOption(const String &name); + DUCKDB_API void ResetOption(const ExtensionOption &extension_option); + DUCKDB_API void ResetGenericOption(idx_t setting_index); + DUCKDB_API optional_idx TryGetSettingIndex(const String &name, + optional_ptr &option) const; static LogicalType ParseLogicalType(const string &type); DUCKDB_API void CheckLock(const String &name); @@ -329,8 +255,11 @@ struct DBConfig { //! Returns the list of possible compression functions for the physical type. DUCKDB_API vector> GetCompressionFunctions(const PhysicalType physical_type); //! Returns the compression function matching the compression and physical type. - DUCKDB_API optional_ptr GetCompressionFunction(CompressionType type, - const PhysicalType physical_type); + //! Throws an error if the function does not exist. + DUCKDB_API reference GetCompressionFunction(CompressionType type, + const PhysicalType physical_type); + DUCKDB_API optional_ptr TryGetCompressionFunction(CompressionType type, + const PhysicalType physical_type); //! Sets the disabled compression methods DUCKDB_API void SetDisabledCompressionMethods(const vector &disabled_compression_methods); //! Returns a list of disabled compression methods @@ -352,6 +281,7 @@ struct DBConfig { bool operator!=(const DBConfig &other); DUCKDB_API CastFunctionSet &GetCastFunctions(); + DUCKDB_API TypeManager &GetTypeManager(); DUCKDB_API CollationBinding &GetCollationBinding(); DUCKDB_API IndexTypeSet &GetIndexTypes(); static idx_t GetSystemMaxThreads(FileSystem &fs); @@ -364,44 +294,29 @@ struct DBConfig { OrderByNullType ResolveNullOrder(ClientContext &context, OrderType order_type, OrderByNullType null_type) const; const string UserAgent() const; + //! Returns the value of a setting currently. If the setting is not set by the user, returns the default value. SettingLookupResult TryGetCurrentSetting(const string &key, Value &result) const; - - template - static typename std::enable_if::value, typename OP::RETURN_TYPE>::type - GetSetting(const SOURCE &source) { - return EnumUtil::FromString( - GetSettingInternal(source, OP::Name, OP::DefaultValue).ToString()); - } - - template - static typename std::enable_if::value, typename OP::RETURN_TYPE>::type - GetSetting(const SOURCE &source) { - return GetSettingInternal(source, OP::Name, OP::DefaultValue).template GetValue(); - } - - template - Value GetSettingValue(const ClientContext &context) const { - lock_guard lock(config_lock); - return OP::GetSetting(context); - } + //! Returns the value of a setting set by the user currently + SettingLookupResult TryGetCurrentUserSetting(idx_t setting_index, Value &result) const; + //! Returns the default value of an option + static SettingLookupResult TryGetDefaultValue(optional_ptr option, Value &result); bool CanAccessFile(const string &path, FileType type); void AddAllowedDirectory(const string &path); void AddAllowedPath(const string &path); string SanitizeAllowedPath(const string &path) const; + ExtensionCallbackManager &GetCallbackManager(); + const ExtensionCallbackManager &GetCallbackManager() const; private: - static Value GetSettingInternal(const DatabaseInstance &db, const char *setting, const char *default_value); - static Value GetSettingInternal(const DBConfig &config, const char *setting, const char *default_value); - static Value GetSettingInternal(const ClientContext &context, const char *setting, const char *default_value); - -private: + mutable mutex config_lock; unique_ptr compression_functions; unique_ptr encoding_functions; unique_ptr arrow_extensions; - unique_ptr cast_functions; + unique_ptr type_manager; unique_ptr collation_bindings; unique_ptr index_types; + unique_ptr callback_manager; bool is_user_config = true; }; diff --git a/src/duckdb/src/include/duckdb/main/connection.hpp b/src/duckdb/src/include/duckdb/main/connection.hpp index 1c88757fc..164dec6b8 100644 --- a/src/duckdb/src/include/duckdb/main/connection.hpp +++ b/src/duckdb/src/include/duckdb/main/connection.hpp @@ -139,9 +139,7 @@ class Connection { //! Extract the logical plan that corresponds to a query DUCKDB_API unique_ptr ExtractPlan(const string &query); - //! Appends a DataChunk to the specified table - DUCKDB_API void Append(TableDescription &description, DataChunk &chunk); - //! Appends a ColumnDataCollection to the specified table + //! Appends a ColumnDataCollection to the described table. DUCKDB_API void Append(TableDescription &description, ColumnDataCollection &collection); //! Returns a relation that produces a table from this connection diff --git a/src/duckdb/src/include/duckdb/main/database.hpp b/src/duckdb/src/include/duckdb/main/database.hpp index 7ecb0bc49..83795046a 100644 --- a/src/duckdb/src/include/duckdb/main/database.hpp +++ b/src/duckdb/src/include/duckdb/main/database.hpp @@ -72,7 +72,8 @@ class DatabaseInstance : public enable_shared_from_this { DUCKDB_API SettingLookupResult TryGetCurrentSetting(const string &key, Value &result) const; - DUCKDB_API shared_ptr GetEncryptionUtil(); + DUCKDB_API shared_ptr GetEncryptionUtil(bool read_only = false); + shared_ptr GetMbedTLSUtil(bool force_mbedtls) const; shared_ptr CreateAttachedDatabase(ClientContext &context, AttachInfo &info, AttachOptions &options); diff --git a/src/duckdb/src/include/duckdb/main/database_manager.hpp b/src/duckdb/src/include/duckdb/main/database_manager.hpp index a2f64e6a5..4e436c0d8 100644 --- a/src/duckdb/src/include/duckdb/main/database_manager.hpp +++ b/src/duckdb/src/include/duckdb/main/database_manager.hpp @@ -39,6 +39,9 @@ class DatabaseManager { static DatabaseManager &Get(ClientContext &db); static DatabaseManager &Get(AttachedDatabase &db); + DatabaseInstance &GetInstance() { + return db; + } //! Initializes the system catalog of the attached SYSTEM_DATABASE. void InitializeSystemCatalog(); //! Finalize starting up the system @@ -108,6 +111,7 @@ class DatabaseManager { shared_ptr database); private: + DatabaseInstance &db; //! The system database is a special database that holds system entries (e.g. functions) shared_ptr system; //! Lock for databases diff --git a/src/duckdb/src/include/duckdb/main/extension/extension_loader.hpp b/src/duckdb/src/include/duckdb/main/extension/extension_loader.hpp index f4f37b558..0914c5449 100644 --- a/src/duckdb/src/include/duckdb/main/extension/extension_loader.hpp +++ b/src/duckdb/src/include/duckdb/main/extension/extension_loader.hpp @@ -73,6 +73,9 @@ class ExtensionLoader { //! Register a new collation DUCKDB_API void RegisterCollation(CreateCollationInfo &info); + //! Register a new coordinate system + DUCKDB_API void RegisterCoordinateSystem(CreateCoordinateSystemInfo &info); + //! Returns a reference to the function in the catalog - throws an exception if it does not exist DUCKDB_API ScalarFunctionCatalogEntry &GetFunction(const string &name); DUCKDB_API TableFunctionCatalogEntry &GetTableFunction(const string &name); diff --git a/src/duckdb/src/include/duckdb/main/extension_callback_manager.hpp b/src/duckdb/src/include/duckdb/main/extension_callback_manager.hpp new file mode 100644 index 000000000..a44108f0f --- /dev/null +++ b/src/duckdb/src/include/duckdb/main/extension_callback_manager.hpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/main/extension_callback_manager.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/mutex.hpp" +#include "duckdb/common/optional_ptr.hpp" +#include "duckdb/common/shared_ptr.hpp" +#include "duckdb/common/vector.hpp" + +namespace duckdb { + +class ClientContext; +class DatabaseInstance; +class ExtensionCallback; +class OperatorExtension; +class OptimizerExtension; +class ParserExtension; +class PlannerExtension; +class StorageExtension; +struct ExtensionCallbackRegistry; + +template +class ExtensionCallbackIteratorHelper; + +class ExtensionCallbackManager { +public: + ExtensionCallbackManager(); + ~ExtensionCallbackManager(); + + static ExtensionCallbackManager &Get(ClientContext &context); + static ExtensionCallbackManager &Get(DatabaseInstance &db); + static const ExtensionCallbackManager &Get(const ClientContext &context); + + void Register(ParserExtension extension); + void Register(PlannerExtension extension); + void Register(OptimizerExtension extension); + void Register(shared_ptr extension); + void Register(const string &name, shared_ptr extension); + void Register(shared_ptr extension); + + ExtensionCallbackIteratorHelper> OperatorExtensions() const; + ExtensionCallbackIteratorHelper OptimizerExtensions() const; + ExtensionCallbackIteratorHelper ParserExtensions() const; + ExtensionCallbackIteratorHelper PlannerExtensions() const; + ExtensionCallbackIteratorHelper> ExtensionCallbacks() const; + optional_ptr FindStorageExtension(const string &name) const; + bool HasParserExtensions() const; + +private: + mutex registry_lock; + shared_ptr callback_registry; +}; + +template +class ExtensionCallbackIteratorHelper { +public: + ExtensionCallbackIteratorHelper(const vector &vec, shared_ptr callback_registry); + ~ExtensionCallbackIteratorHelper(); + +private: + const vector &vec; + shared_ptr callback_registry; + +public: + typename vector::const_iterator begin() { // NOLINT: match stl API + return vec.cbegin(); + } + typename vector::const_iterator end() { // NOLINT: match stl API + return vec.cend(); + } +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/extension_entries.hpp b/src/duckdb/src/include/duckdb/main/extension_entries.hpp index df7a0a7c3..ec2afe8ae 100644 --- a/src/duckdb/src/include/duckdb/main/extension_entries.hpp +++ b/src/duckdb/src/include/duckdb/main/extension_entries.hpp @@ -149,6 +149,7 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"decode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"degrees", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"delta_scan", "delta", CatalogType::TABLE_FUNCTION_ENTRY}, + {"disable_peg_parser", "autocomplete", CatalogType::TABLE_FUNCTION_ENTRY}, {"drop_fts_index", "fts", CatalogType::PRAGMA_FUNCTION_ENTRY}, {"dsdgen", "tpcds", CatalogType::TABLE_FUNCTION_ENTRY}, {"duckdb_proj_compiled_version", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -166,6 +167,7 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"ducklake_rewrite_data_files", "ducklake", CatalogType::TABLE_FUNCTION_ENTRY}, {"ducklake_set_commit_message", "ducklake", CatalogType::TABLE_FUNCTION_ENTRY}, {"ducklake_set_option", "ducklake", CatalogType::TABLE_FUNCTION_ENTRY}, + {"ducklake_settings", "ducklake", CatalogType::TABLE_FUNCTION_ENTRY}, {"ducklake_snapshots", "ducklake", CatalogType::TABLE_FUNCTION_ENTRY}, {"ducklake_table_changes", "ducklake", CatalogType::TABLE_MACRO_ENTRY}, {"ducklake_table_deletions", "ducklake", CatalogType::TABLE_FUNCTION_ENTRY}, @@ -173,6 +175,7 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"ducklake_table_insertions", "ducklake", CatalogType::TABLE_FUNCTION_ENTRY}, {"editdist3", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"element_at", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"enable_peg_parser", "autocomplete", CatalogType::TABLE_FUNCTION_ENTRY}, {"encode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"entropy", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"enum_code", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -211,6 +214,7 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"get_bit", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"get_current_time", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, {"get_current_timestamp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"get_type", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"grade_up", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"greatest", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"greatest_common_divisor", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -453,6 +457,7 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"make_timestamp_ms", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"make_timestamp_ns", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"make_timestamptz", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"make_type", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"map", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"map_concat", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"map_entries", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -476,6 +481,17 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"nextafter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"normalized_interval", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"now", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"odbc_begin_transaction", "odbc_scanner", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"odbc_bind_params", "odbc_scanner", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"odbc_close", "odbc_scanner", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"odbc_commit", "odbc_scanner", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"odbc_connect", "odbc_scanner", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"odbc_copy", "odbc_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, + {"odbc_create_params", "odbc_scanner", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"odbc_list_data_sources", "odbc_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, + {"odbc_list_drivers", "odbc_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, + {"odbc_query", "odbc_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, + {"odbc_rollback", "odbc_scanner", CatalogType::SCALAR_FUNCTION_ENTRY}, {"ord", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"parquet_bloom_probe", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_file_metadata", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, @@ -521,7 +537,6 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"read_xlsx", "excel", CatalogType::TABLE_FUNCTION_ENTRY}, {"reduce", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"reduce_sql_statement", "sqlsmith", CatalogType::TABLE_FUNCTION_ENTRY}, - {"register_geoarrow_extensions", "spatial", CatalogType::TABLE_FUNCTION_ENTRY}, {"regr_avgx", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"regr_avgy", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"regr_count", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, @@ -570,8 +585,6 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"st_asmvt", "spatial", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"st_asmvtgeom", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_assvg", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"st_astext", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"st_aswkb", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_azimuth", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_boundary", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_buffer", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -624,15 +637,14 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"st_geomfromhexewkb", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_geomfromhexwkb", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_geomfromtext", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"st_geomfromwkb", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_hasm", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_hasz", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_hilbert", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"st_interiorringn", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_interpolatepoint", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_intersection", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_intersection_agg", "spatial", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"st_intersects", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"st_intersects_extent", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_isclosed", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_isempty", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_isring", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -1021,6 +1033,7 @@ static constexpr ExtensionFunctionOverloadEntry EXTENSION_FUNCTION_OVERLOADS[] = }; // END_OF_EXTENSION_FUNCTION_OVERLOADS static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { + {"allow_asterisks_in_http_paths", "httpfs"}, {"auto_fallback_to_full_download", "httpfs"}, {"azure_account_name", "azure"}, {"azure_context_caching", "azure"}, @@ -1044,6 +1057,7 @@ static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"ducklake_retry_wait_ms", "ducklake"}, {"enable_curl_server_cert_verification", "httpfs"}, {"enable_geoparquet_conversion", "parquet"}, + {"enable_global_s3_configuration", "httpfs"}, {"enable_server_cert_verification", "httpfs"}, {"force_download", "httpfs"}, {"hf_max_per_page", "httpfs"}, @@ -1055,10 +1069,14 @@ static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"http_retry_wait_ms", "httpfs"}, {"http_timeout", "httpfs"}, {"httpfs_client_implementation", "httpfs"}, + {"iceberg_test_force_token_expiry", "iceberg"}, {"iceberg_via_aws_sdk_for_catalog_interactions", "iceberg"}, + {"merge_http_secret_into_s3_request", "httpfs"}, {"mysql_bit1_as_boolean", "mysql_scanner"}, {"mysql_debug_show_queries", "mysql_scanner"}, + {"mysql_enable_transactions", "mysql_scanner"}, {"mysql_experimental_filter_pushdown", "mysql_scanner"}, + {"mysql_incomplete_dates_as_nulls", "mysql_scanner"}, {"mysql_session_time_zone", "mysql_scanner"}, {"mysql_time_as_time", "mysql_scanner"}, {"mysql_tinyint1_as_boolean", "mysql_scanner"}, @@ -1075,6 +1093,7 @@ static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"pg_use_text_protocol", "postgres_scanner"}, {"prefetch_all_parquet_files", "parquet"}, {"s3_access_key_id", "httpfs"}, + {"s3_allow_recursive_globbing", "httpfs"}, {"s3_endpoint", "httpfs"}, {"s3_kms_key_id", "httpfs"}, {"s3_region", "httpfs"}, @@ -1087,6 +1106,7 @@ static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"s3_url_compatibility_mode", "httpfs"}, {"s3_url_style", "httpfs"}, {"s3_use_ssl", "httpfs"}, + {"s3_version_id_pinning", "httpfs"}, {"sqlite_all_varchar", "sqlite_scanner"}, {"sqlite_debug_show_queries", "sqlite_scanner"}, {"timezone", "icu"}, @@ -1203,7 +1223,7 @@ static constexpr const char *AUTOLOADABLE_EXTENSIONS[] = {"avro", "postgres_scanner", "tpcds", "tpch", - "uc_catalog", + "unity_catalog", "ui"}; // END_OF_AUTOLOADABLE_EXTENSIONS } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/extension_helper.hpp b/src/duckdb/src/include/duckdb/main/extension_helper.hpp index 480bc398f..6dd63f7db 100644 --- a/src/duckdb/src/include/duckdb/main/extension_helper.hpp +++ b/src/duckdb/src/include/duckdb/main/extension_helper.hpp @@ -11,6 +11,7 @@ #include "duckdb.hpp" #include "duckdb/main/extension_entries.hpp" #include "duckdb/main/extension_install_info.hpp" +#include "duckdb/main/settings.hpp" #include @@ -126,8 +127,15 @@ class ExtensionHelper { static vector GetExtensionDirectoryPath(ClientContext &context); static vector GetExtensionDirectoryPath(DatabaseInstance &db, FileSystem &fs); + // Check signature of an Extension stored as FileHandle static bool CheckExtensionSignature(FileHandle &handle, ParsedExtensionMetaData &parsed_metadata, const bool allow_community_extensions); + // Check signature of an Extension, represented by a buffer and total_buffer_length, and a signature to be added + static bool CheckExtensionBufferSignature(const char *buffer, idx_t buffer_length, const string &signature, + const bool allow_community_extensions); + // Check signature of an Extension, represented by a buffer and total_buffer_length + static bool CheckExtensionBufferSignature(const char *buffer, idx_t total_buffer_length, + const bool allow_community_extensions); static ParsedExtensionMetaData ParseExtensionMetaData(const char *metadata) noexcept; static ParsedExtensionMetaData ParseExtensionMetaData(FileHandle &handle); @@ -207,9 +215,8 @@ class ExtensionHelper { //! Lookup a name in an extension entry and try to autoload it template static void TryAutoloadFromEntry(DatabaseInstance &db, const string &entry, const ExtensionEntry (&entries)[N]) { - auto &dbconfig = DBConfig::GetConfig(db); #ifndef DUCKDB_DISABLE_EXTENSION_LOAD - if (dbconfig.options.autoload_known_extensions) { + if (Settings::Get(db)) { auto extension_name = ExtensionHelper::FindExtensionInEntries(entry, entries); if (ExtensionHelper::CanAutoloadExtension(extension_name)) { ExtensionHelper::AutoLoadExtension(db, extension_name); diff --git a/src/duckdb/src/include/duckdb/main/prepared_statement.hpp b/src/duckdb/src/include/duckdb/main/prepared_statement.hpp index a391f6ac4..0f8b86a07 100644 --- a/src/duckdb/src/include/duckdb/main/prepared_statement.hpp +++ b/src/duckdb/src/include/duckdb/main/prepared_statement.hpp @@ -152,6 +152,9 @@ class PreparedStatement { } } + //! Returns whether or not we can / want to cache a logical plan + static bool CanCachePlan(const LogicalOperator &op); + private: unique_ptr PendingQueryRecursive(vector &values) { return PendingQuery(values); diff --git a/src/duckdb/src/include/duckdb/main/profiling_utils.hpp b/src/duckdb/src/include/duckdb/main/profiling_utils.hpp index 037619309..5b4438969 100644 --- a/src/duckdb/src/include/duckdb/main/profiling_utils.hpp +++ b/src/duckdb/src/include/duckdb/main/profiling_utils.hpp @@ -53,6 +53,9 @@ struct QueryMetrics { for(idx_t i = 0; i < ACTIVELY_TRACKED_METRICS; i++) { active_metrics[i] = 0; } + + latency_timer.reset(); + query_name = ""; } void Merge(const QueryMetrics &other) { @@ -94,6 +97,8 @@ class ProfilingUtils { struct ActiveTimer { public: + ActiveTimer() : metric(MetricType::EXTRA_INFO), is_active(false) { + } ActiveTimer(QueryMetrics &query_metrics, const MetricType metric, const bool is_active = true) : query_metrics(query_metrics), metric(metric), is_active(is_active) { // start on constructor if (!is_active) { @@ -101,13 +106,29 @@ struct ActiveTimer { } profiler.Start(); } - ~ActiveTimer() { if (is_active) { // automatically end in destructor EndTimer(); } } + // disable copy constructors + ActiveTimer(const ActiveTimer &other) = delete; + ActiveTimer &operator=(const ActiveTimer &) = delete; + //! enable move constructors + ActiveTimer(ActiveTimer &&other) noexcept : is_active(false) { + std::swap(query_metrics, other.query_metrics); + std::swap(metric, other.metric); + std::swap(profiler, other.profiler); + std::swap(is_active, other.is_active); + } + ActiveTimer &operator=(ActiveTimer &&other) noexcept { + std::swap(query_metrics, other.query_metrics); + std::swap(metric, other.metric); + std::swap(profiler, other.profiler); + std::swap(is_active, other.is_active); + return *this; + } // Automatically called in the destructor. void EndTimer() { @@ -117,7 +138,7 @@ struct ActiveTimer { // stop profiling and report is_active = false; profiler.End(); - query_metrics.UpdateMetric(metric, profiler.ElapsedNanos()); + query_metrics->UpdateMetric(metric, profiler.ElapsedNanos()); } void Reset() { @@ -129,8 +150,8 @@ struct ActiveTimer { } private: - QueryMetrics &query_metrics; - const MetricType metric; + optional_ptr query_metrics; + MetricType metric; Profiler profiler; bool is_active; }; diff --git a/src/duckdb/src/include/duckdb/main/query_profiler.hpp b/src/duckdb/src/include/duckdb/main/query_profiler.hpp index ca3f8bcf6..50c78febf 100644 --- a/src/duckdb/src/include/duckdb/main/query_profiler.hpp +++ b/src/duckdb/src/include/duckdb/main/query_profiler.hpp @@ -144,6 +144,8 @@ class QueryProfiler { DUCKDB_API void Reset(); DUCKDB_API void StartQuery(const string &query, bool is_explain_analyze = false, bool start_at_optimizer = false); DUCKDB_API void EndQuery(); + //! Finalize query metrics for output; safe to call multiple times. + DUCKDB_API void FinalizeMetrics(); //! Adds amount to a specific metric type. DUCKDB_API void AddToCounter(MetricType type, const idx_t amount); @@ -227,6 +229,8 @@ class QueryProfiler { TreeMap tree_map; //! Whether or not we are running as part of a explain_analyze query bool is_explain_analyze; + //! Whether root metrics have been finalized for output + bool metrics_finalized; public: const TreeMap &GetTreeMap() const { @@ -245,6 +249,7 @@ class QueryProfiler { private: void MoveOptimizerPhasesToRoot(); + void FinalizeMetricsInternal(); //! 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. diff --git a/src/duckdb/src/include/duckdb/main/secret/secret.hpp b/src/duckdb/src/include/duckdb/main/secret/secret.hpp index fd8a1b241..cc6ad1c94 100644 --- a/src/duckdb/src/include/duckdb/main/secret/secret.hpp +++ b/src/duckdb/src/include/duckdb/main/secret/secret.hpp @@ -252,7 +252,7 @@ class KeyValueSecret : public BaseSecret { class KeyValueSecretReader { public: //! Manually pass in a secret reference - KeyValueSecretReader(const KeyValueSecret &secret_p, FileOpener &opener_p) : secret(secret_p) {}; + KeyValueSecretReader(const KeyValueSecret &secret_p, FileOpener &opener_p); //! Initializes the KeyValueSecretReader by fetching the secret automatically KeyValueSecretReader(FileOpener &opener_p, optional_ptr info, const char **secret_types, diff --git a/src/duckdb/src/include/duckdb/main/secret/secret_manager.hpp b/src/duckdb/src/include/duckdb/main/secret/secret_manager.hpp index 80fb46044..8ba703dcd 100644 --- a/src/duckdb/src/include/duckdb/main/secret/secret_manager.hpp +++ b/src/duckdb/src/include/duckdb/main/secret/secret_manager.hpp @@ -16,8 +16,10 @@ #include "duckdb/parser/parsed_data/create_secret_info.hpp" namespace duckdb { -class SecretManager; + +struct BoundStatement; struct DBConfig; +class SecretManager; class SchemaCatalogEntry; //! A Secret Entry in the secret manager @@ -217,6 +219,9 @@ class DefaultSecretGenerator : public DefaultGenerator { unique_ptr CreateDefaultEntry(CatalogTransaction transaction, const string &entry_name) override; unique_ptr CreateDefaultEntry(ClientContext &context, const string &entry_name) override; vector GetDefaultEntries() override; + bool LockDuringCreate() const override { + return true; + } protected: unique_ptr CreateDefaultEntryInternal(const string &entry_name); diff --git a/src/duckdb/src/include/duckdb/main/setting_info.hpp b/src/duckdb/src/include/duckdb/main/setting_info.hpp index 7968c4d8f..8aaa19223 100644 --- a/src/duckdb/src/include/duckdb/main/setting_info.hpp +++ b/src/duckdb/src/include/duckdb/main/setting_info.hpp @@ -17,8 +17,6 @@ class ClientContext; class DatabaseInstance; struct DBConfig; -const string GetDefaultUserAgent(); - enum class SettingScope : uint8_t { //! Setting is from the global Setting scope GLOBAL, @@ -30,6 +28,18 @@ enum class SettingScope : uint8_t { INVALID }; +enum class SettingScopeTarget { + INVALID, + //! Setting can be set in global scope only + GLOBAL_ONLY, + //! Setting can be set in local scope only + LOCAL_ONLY, + //! Setting can be set in both scopes - but defaults to global + GLOBAL_DEFAULT, + //! Setting can be set in both scopes - but defaults to local + LOCAL_DEFAULT +}; + struct SettingLookupResult { public: SettingLookupResult() : scope(SettingScope::INVALID) { @@ -79,9 +89,10 @@ struct ConfigurationOption { reset_global_function_t reset_global; reset_local_function_t reset_local; get_setting_function_t get_setting; - SetScope default_scope; + SettingScopeTarget scope; const char *default_value; set_callback_t set_callback; + optional_idx setting_idx; }; struct ConfigurationAlias { @@ -92,6 +103,8 @@ struct ConfigurationAlias { typedef void (*set_option_callback_t)(ClientContext &context, SetScope scope, Value ¶meter); struct ExtensionOption { + ExtensionOption() : set_function(nullptr), default_scope(SetScope::AUTOMATIC) { + } // NOLINTNEXTLINE: work around bug in clang-tidy ExtensionOption(string description_p, LogicalType type_p, set_option_callback_t set_function_p, Value default_value_p, SetScope default_scope_p) @@ -104,6 +117,7 @@ struct ExtensionOption { set_option_callback_t set_function; Value default_value; SetScope default_scope; + optional_idx setting_index; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/settings.hpp b/src/duckdb/src/include/duckdb/main/settings.hpp index d87f8aa1a..b85b00db9 100644 --- a/src/duckdb/src/include/duckdb/main/settings.hpp +++ b/src/duckdb/src/include/duckdb/main/settings.hpp @@ -8,21 +8,78 @@ #pragma once -#include "duckdb/main/config.hpp" #include "duckdb/main/setting_info.hpp" -#include "duckdb/common/enums/access_mode.hpp" -#include "duckdb/common/enums/cache_validation_mode.hpp" -#include "duckdb/common/enums/checkpoint_abort.hpp" -#include "duckdb/common/enums/debug_vector_verification.hpp" -#include "duckdb/common/enums/window_aggregation_mode.hpp" -#include "duckdb/common/enums/order_type.hpp" -#include "duckdb/common/enums/output_type.hpp" -#include "duckdb/common/enums/thread_pin_mode.hpp" -#include "duckdb/common/enums/arrow_format_version.hpp" -#include "duckdb/common/enums/storage_block_prefetch.hpp" +#include "duckdb/common/enum_util.hpp" namespace duckdb { +struct Settings { + template + static typename std::enable_if::value, typename OP::RETURN_TYPE>::type + Get(const SOURCE &source) { + Value result; + if (TryGetSettingInternal(source, OP::SettingIndex, result) && !result.IsNull()) { + return EnumUtil::FromString(StringValue::Get(result)); + } + return EnumUtil::FromString(OP::DefaultValue); + } + + template + static typename std::enable_if::value, string>::type + Get(const SOURCE &source) { + Value result; + if (TryGetSettingInternal(source, OP::SettingIndex, result) && !result.IsNull()) { + return StringValue::Get(result); + } + return OP::DefaultValue; + } + + template + static typename std::enable_if::value, bool>::type + Get(const SOURCE &source) { + Value result; + if (TryGetSettingInternal(source, OP::SettingIndex, result) && !result.IsNull()) { + return BooleanValue::Get(result); + } + return StringUtil::Equals(OP::DefaultValue, "true"); + } + + template + static typename std::enable_if::value, idx_t>::type + Get(const SOURCE &source) { + Value result; + if (TryGetSettingInternal(source, OP::SettingIndex, result) && !result.IsNull()) { + return UBigIntValue::Get(result); + } + return StringUtil::ToUnsigned(OP::DefaultValue); + } + + template + static typename std::enable_if::value, int64_t>::type + Get(const SOURCE &source) { + Value result; + if (TryGetSettingInternal(source, OP::SettingIndex, result) && !result.IsNull()) { + return BigIntValue::Get(result); + } + return StringUtil::ToSigned(OP::DefaultValue); + } + + template + static typename std::enable_if::value, double>::type + Get(const SOURCE &source) { + Value result; + if (TryGetSettingInternal(source, OP::SettingIndex, result) && !result.IsNull()) { + return DoubleValue::Get(result); + } + return StringUtil::ToDouble(OP::DefaultValue); + } + +private: + static bool TryGetSettingInternal(const DatabaseInstance &db, idx_t setting_index, Value &result); + static bool TryGetSettingInternal(const DBConfig &config, idx_t setting_index, Value &result); + static bool TryGetSettingInternal(const ClientContext &context, idx_t setting_index, Value &result); +}; + //===----------------------------------------------------------------------===// // This code is autogenerated from 'update_settings_header_file.py'. // Please do not make any changes directly here, as they will be overwritten. @@ -46,11 +103,10 @@ struct AllocatorBackgroundThreadsSetting { static constexpr const char *Name = "allocator_background_threads"; static constexpr const char *Description = "Whether to enable the allocator background thread."; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 0; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct AllocatorBulkDeallocationFlushThresholdSetting { @@ -80,11 +136,10 @@ struct AllowCommunityExtensionsSetting { static constexpr const char *Name = "allow_community_extensions"; static constexpr const char *Description = "Allow to load community built extensions"; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "true"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 1; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct AllowExtensionsMetadataMismatchSetting { @@ -93,19 +148,19 @@ struct AllowExtensionsMetadataMismatchSetting { static constexpr const char *Description = "Allow to load extensions with not compatible metadata"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 2; }; struct AllowParserOverrideExtensionSetting { - using RETURN_TYPE = string; + using RETURN_TYPE = AllowParserOverride; static constexpr const char *Name = "allow_parser_override_extension"; static constexpr const char *Description = "Allow extensions to override the current parser"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "DEFAULT"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 3; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct AllowPersistentSecretsSetting { @@ -124,11 +179,10 @@ struct AllowUnredactedSecretsSetting { static constexpr const char *Name = "allow_unredacted_secrets"; static constexpr const char *Description = "Allow printing unredacted secrets"; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 4; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct AllowUnsignedExtensionsSetting { @@ -136,11 +190,10 @@ struct AllowUnsignedExtensionsSetting { static constexpr const char *Name = "allow_unsigned_extensions"; static constexpr const char *Description = "Allow to load extensions with invalid or missing signatures"; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 5; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct AllowedDirectoriesSetting { @@ -172,7 +225,8 @@ struct ArrowLargeBufferSizeSetting { "Whether Arrow buffers for strings, blobs, uuids and bits should be exported using large buffers"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 6; }; struct ArrowLosslessConversionSetting { @@ -183,7 +237,8 @@ struct ArrowLosslessConversionSetting { "with a duckdb.type_name extension name."; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 7; }; struct ArrowOutputListViewSetting { @@ -193,7 +248,8 @@ struct ArrowOutputListViewSetting { "Whether export to Arrow format should use ListView as the physical layout for LIST columns"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 8; }; struct ArrowOutputVersionSetting { @@ -203,7 +259,8 @@ struct ArrowOutputVersionSetting { "Whether strings should be produced by DuckDB in Utf8View format instead of Utf8"; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = "1.0"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 9; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -214,7 +271,20 @@ struct AsofLoopJoinThresholdSetting { "The maximum number of rows we need on the left side of an ASOF join to use a nested loop join"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "64"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 10; +}; + +struct AutoCheckpointSkipWalThresholdSetting { + using RETURN_TYPE = idx_t; + static constexpr const char *Name = "auto_checkpoint_skip_wal_threshold"; + static constexpr const char *Description = + "The estimated WAL write size at which point we will skip writing to the WAL and only checkpoint. Skipping " + "writing to the WAL means concurrent commits are blocked while the checkpoint is happening."; + static constexpr const char *InputType = "UBIGINT"; + static constexpr const char *DefaultValue = "100000"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 11; }; struct AutoinstallExtensionRepositorySetting { @@ -223,9 +293,9 @@ struct AutoinstallExtensionRepositorySetting { static constexpr const char *Description = "Overrides the custom endpoint for extension installation on autoloading"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 12; }; struct AutoinstallKnownExtensionsSetting { @@ -234,9 +304,13 @@ struct AutoinstallKnownExtensionsSetting { static constexpr const char *Description = "Whether known extensions are allowed to be automatically installed when a query depends on them"; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); +#if defined(DUCKDB_EXTENSION_AUTOINSTALL_DEFAULT) && DUCKDB_EXTENSION_AUTOINSTALL_DEFAULT + static constexpr const char *DefaultValue = "true"; +#else + static constexpr const char *DefaultValue = "false"; +#endif + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 13; }; struct AutoloadKnownExtensionsSetting { @@ -245,9 +319,13 @@ struct AutoloadKnownExtensionsSetting { static constexpr const char *Description = "Whether known extensions are allowed to be automatically loaded when a query depends on them"; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); +#if defined(DUCKDB_EXTENSION_AUTOLOAD_DEFAULT) && DUCKDB_EXTENSION_AUTOLOAD_DEFAULT + static constexpr const char *DefaultValue = "true"; +#else + static constexpr const char *DefaultValue = "false"; +#endif + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 14; }; struct BlockAllocatorMemorySetting { @@ -268,7 +346,8 @@ struct CatalogErrorMaxSchemasSetting { "The maximum number of schemas the system will scan for \"did you mean...\" style errors in the catalog"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "100"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 15; }; struct CheckpointThresholdSetting { @@ -287,9 +366,9 @@ struct CustomExtensionRepositorySetting { static constexpr const char *Name = "custom_extension_repository"; static constexpr const char *Description = "Overrides the custom endpoint for remote extension installation"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 16; }; struct CustomProfilingSettingsSetting { @@ -318,7 +397,8 @@ struct DebugAsofIejoinSetting { static constexpr const char *Description = "DEBUG SETTING: force use of IEJoin to implement AsOf joins"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 17; }; struct DebugCheckpointAbortSetting { @@ -328,7 +408,8 @@ struct DebugCheckpointAbortSetting { "DEBUG SETTING: trigger an abort while checkpointing for testing purposes"; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = "NONE"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 18; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -338,7 +419,19 @@ struct DebugCheckpointSleepMsSetting { static constexpr const char *Description = "DEBUG SETTING: time to sleep before a checkpoint"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "0"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 19; +}; + +struct DebugEvictionQueueSleepMicroSecondsSetting { + using RETURN_TYPE = idx_t; + static constexpr const char *Name = "debug_eviction_queue_sleep_micro_seconds"; + static constexpr const char *Description = + "DEBUG SETTING: time for the eviction queue to sleep before acquiring shared ownership of block memory"; + static constexpr const char *InputType = "UBIGINT"; + static constexpr const char *DefaultValue = "0"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 20; }; struct DebugForceExternalSetting { @@ -359,7 +452,8 @@ struct DebugForceNoCrossProductSetting { "DEBUG SETTING: Force disable cross product generation when hyper graph isn't connected, used for testing"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 21; }; struct DebugPhysicalTableScanExecutionStrategySetting { @@ -369,7 +463,8 @@ struct DebugPhysicalTableScanExecutionStrategySetting { "DEBUG SETTING: force use of given strategy for executing physical table scans"; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = "DEFAULT"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 22; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -379,7 +474,8 @@ struct DebugSkipCheckpointOnCommitSetting { static constexpr const char *Description = "DEBUG SETTING: skip checkpointing on commit"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 23; }; struct DebugVerifyBlocksSetting { @@ -388,7 +484,8 @@ struct DebugVerifyBlocksSetting { static constexpr const char *Description = "DEBUG SETTING: verify block metadata during checkpointing"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 24; }; struct DebugVerifyVectorSetting { @@ -397,7 +494,8 @@ struct DebugVerifyVectorSetting { static constexpr const char *Description = "DEBUG SETTING: enable vector verification"; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = "NONE"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 25; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -407,7 +505,8 @@ struct DebugWindowModeSetting { static constexpr const char *Description = "DEBUG SETTING: switch window mode to use"; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = "WINDOW"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 26; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -417,9 +516,10 @@ struct DefaultBlockSizeSetting { static constexpr const char *Description = "The default block size for new duckdb database files (new as-in, they do not yet exist)."; static constexpr const char *InputType = "UBIGINT"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "262144"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 27; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct DefaultCollationSetting { @@ -428,7 +528,8 @@ struct DefaultCollationSetting { static constexpr const char *Description = "The collation setting used when none is specified"; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = ""; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 28; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -438,7 +539,8 @@ struct DefaultNullOrderSetting { static constexpr const char *Description = "NULL ordering used when none is specified (NULLS_FIRST or NULLS_LAST)"; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = "NULLS_LAST"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 29; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -448,7 +550,8 @@ struct DefaultOrderSetting { static constexpr const char *Description = "The order type used when none is specified (ASC or DESC)"; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = "ASCENDING"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 30; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -462,6 +565,17 @@ struct DefaultSecretStorageSetting { static Value GetSetting(const ClientContext &context); }; +struct DeprecatedUsingKeySyntaxSetting { + using RETURN_TYPE = DeprecatedUsingKeySyntax; + static constexpr const char *Name = "deprecated_using_key_syntax"; + static constexpr const char *Description = "Configures the use of the deprecated union syntax for USING KEY CTEs."; + static constexpr const char *InputType = "VARCHAR"; + static constexpr const char *DefaultValue = "DEFAULT"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 31; + static void OnSet(SettingCallbackInfo &info, Value &input); +}; + struct DisableDatabaseInvalidationSetting { using RETURN_TYPE = bool; static constexpr const char *Name = "disable_database_invalidation"; @@ -469,11 +583,10 @@ struct DisableDatabaseInvalidationSetting { "Disables invalidating the database instance when encountering a fatal error. Should be used with great care, " "as DuckDB cannot guarantee correct behavior after a fatal error."; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 32; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct DisableTimestamptzCastsSetting { @@ -482,7 +595,8 @@ struct DisableTimestamptzCastsSetting { static constexpr const char *Description = "Disable casting from timestamp to timestamptz "; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 33; }; struct DisabledCompressionMethodsSetting { @@ -530,9 +644,10 @@ struct DuckDBAPISetting { static constexpr const char *Name = "duckdb_api"; static constexpr const char *Description = "DuckDB API surface"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 34; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct DynamicOrFilterThresholdSetting { @@ -542,7 +657,8 @@ struct DynamicOrFilterThresholdSetting { "The maximum amount of OR filters we generate dynamically from a hash join"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "50"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 35; }; struct EnableExternalAccessSetting { @@ -552,11 +668,10 @@ struct EnableExternalAccessSetting { "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 char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "true"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 36; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct EnableExternalFileCacheSetting { @@ -564,9 +679,10 @@ struct EnableExternalFileCacheSetting { static constexpr const char *Name = "enable_external_file_cache"; static constexpr const char *Description = "Allow the database to cache external files (e.g., Parquet) in memory."; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "true"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 37; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct EnableFSSTVectorsSetting { @@ -576,7 +692,8 @@ struct EnableFSSTVectorsSetting { "Allow scans on FSST compressed segments to emit compressed vectors to utilize late decompression"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 38; }; struct EnableHTTPLoggingSetting { @@ -594,9 +711,9 @@ struct EnableHTTPMetadataCacheSetting { static constexpr const char *Name = "enable_http_metadata_cache"; static constexpr const char *Description = "Whether or not the global http metadata is used to cache HTTP metadata"; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 39; }; struct EnableLogging { @@ -616,7 +733,8 @@ struct EnableMacroDependenciesSetting { "Enable created MACROs to create dependencies on the referenced objects (such as tables)"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 40; }; struct EnableObjectCacheSetting { @@ -625,7 +743,8 @@ struct EnableObjectCacheSetting { static constexpr const char *Description = "[PLACEHOLDER] Legacy setting - does nothing"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 41; }; struct EnableProfilingSetting { @@ -670,7 +789,8 @@ struct EnableViewDependenciesSetting { "Enable created VIEWs to create dependencies on the referenced objects (such as tables)"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 42; }; struct EnabledLogTypes { @@ -688,9 +808,9 @@ struct ErrorsAsJSONSetting { static constexpr const char *Name = "errors_as_json"; static constexpr const char *Description = "Output error messages as structured JSON instead of as a raw string"; static constexpr const char *InputType = "BOOLEAN"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 43; }; struct ExperimentalMetadataReuseSetting { @@ -699,7 +819,8 @@ struct ExperimentalMetadataReuseSetting { static constexpr const char *Description = "EXPERIMENTAL: Re-use row group and table metadata when checkpointing."; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "true"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 44; }; struct ExplainOutputSetting { @@ -707,9 +828,10 @@ 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 char *InputType = "VARCHAR"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "PHYSICAL_ONLY"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 45; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct ExtensionDirectoriesSetting { @@ -727,9 +849,9 @@ struct ExtensionDirectorySetting { static constexpr const char *Name = "extension_directory"; static constexpr const char *Description = "Set the directory to store extensions in"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 46; }; struct ExternalThreadsSetting { @@ -737,11 +859,10 @@ 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 char *InputType = "UBIGINT"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "1"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 47; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct FileSearchPathSetting { @@ -749,26 +870,38 @@ 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 char *InputType = "VARCHAR"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 48; }; struct ForceBitpackingModeSetting { - using RETURN_TYPE = string; + using RETURN_TYPE = BitpackingMode; static constexpr const char *Name = "force_bitpacking_mode"; static constexpr const char *Description = "DEBUG SETTING: forces a specific bitpacking mode"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "AUTO"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 49; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct ForceCompressionSetting { - using RETURN_TYPE = string; + using RETURN_TYPE = CompressionType; 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 char *InputType = "VARCHAR"; + static constexpr const char *DefaultValue = "auto"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 50; + static void OnSet(SettingCallbackInfo &info, Value &input); +}; + +struct ForceMbedtlsUnsafeSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "force_mbedtls_unsafe"; + static constexpr const char *Description = "Enable mbedtls for encryption (WARNING: unsafe to use)"; + static constexpr const char *InputType = "BOOLEAN"; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); @@ -785,14 +918,26 @@ struct ForceVariantShredding { static Value GetSetting(const ClientContext &context); }; +struct GeometryMinimumShreddingSize { + using RETURN_TYPE = int64_t; + static constexpr const char *Name = "geometry_minimum_shredding_size"; + static constexpr const char *Description = "Minimum size of a rowgroup to enable GEOMETRY shredding, or set to -1 " + "to disable entirely. Defaults to 1/4th of a rowgroup"; + static constexpr const char *InputType = "BIGINT"; + static constexpr const char *DefaultValue = "30000"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 51; +}; + struct HomeDirectorySetting { using RETURN_TYPE = string; static constexpr const char *Name = "home_directory"; static constexpr const char *Description = "Sets the home directory used by the system"; static constexpr const char *InputType = "VARCHAR"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 52; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct HTTPLoggingOutputSetting { @@ -811,9 +956,9 @@ struct HTTPProxySetting { static constexpr const char *Name = "http_proxy"; static constexpr const char *Description = "HTTP proxy host"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 53; }; struct HTTPProxyPasswordSetting { @@ -821,9 +966,9 @@ struct HTTPProxyPasswordSetting { static constexpr const char *Name = "http_proxy_password"; static constexpr const char *Description = "Password for HTTP proxy"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 54; }; struct HTTPProxyUsernameSetting { @@ -831,9 +976,9 @@ struct HTTPProxyUsernameSetting { static constexpr const char *Name = "http_proxy_username"; static constexpr const char *Description = "Username for HTTP proxy"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 55; }; struct IeeeFloatingPointOpsSetting { @@ -843,7 +988,19 @@ struct IeeeFloatingPointOpsSetting { "Use IEE754-compliant floating point operations (returning NAN instead of errors/NULL)."; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "true"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 56; +}; + +struct IgnoreUnknownCrsSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "ignore_unknown_crs"; + static constexpr const char *Description = + "Ignore unknown Coordinate Reference Systems (CRS) when creating geometry types or importing geospatial data."; + static constexpr const char *InputType = "BOOLEAN"; + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 57; }; struct ImmediateTransactionModeSetting { @@ -853,7 +1010,8 @@ struct ImmediateTransactionModeSetting { "Whether transactions should be started lazily when needed, or immediately when BEGIN TRANSACTION is called"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 58; }; struct IndexScanMaxCountSetting { @@ -864,7 +1022,8 @@ struct IndexScanMaxCountSetting { "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "2048"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 59; }; struct IndexScanPercentageSetting { @@ -875,7 +1034,8 @@ struct IndexScanPercentageSetting { "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; static constexpr const char *InputType = "DOUBLE"; static constexpr const char *DefaultValue = "0.001"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 60; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -886,18 +1046,20 @@ struct IntegerDivisionSetting { "Whether or not the / operator defaults to integer division, or to floating point division"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 61; }; struct LambdaSyntaxSetting { - using RETURN_TYPE = string; + using RETURN_TYPE = LambdaSyntax; static constexpr const char *Name = "lambda_syntax"; static constexpr const char *Description = "Configures the use of the deprecated single arrow operator (->) for lambda functions."; static constexpr const char *InputType = "VARCHAR"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "DEFAULT"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 62; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct LateMaterializationMaxRowsSetting { @@ -907,7 +1069,8 @@ struct LateMaterializationMaxRowsSetting { "The maximum amount of rows in the LIMIT/SAMPLE for which we trigger late materialization"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "50"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 63; }; struct LockConfigurationSetting { @@ -915,9 +1078,9 @@ struct LockConfigurationSetting { static constexpr const char *Name = "lock_configuration"; static constexpr const char *Description = "Whether or not the configuration can be altered"; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 64; }; struct LogQueryPathSetting { @@ -926,9 +1089,10 @@ struct LogQueryPathSetting { static constexpr const char *Description = "Specifies the path to which queries should be logged (default: NULL, queries are not logged)"; static constexpr const char *InputType = "VARCHAR"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 65; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct LoggingLevel { @@ -968,9 +1132,9 @@ struct MaxExpressionDepthSetting { "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 char *InputType = "UBIGINT"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "1000"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 66; }; struct MaxMemorySetting { @@ -1000,7 +1164,8 @@ struct MaxVacuumTasksSetting { static constexpr const char *Description = "The maximum vacuum tasks to schedule during a checkpoint."; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "100"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 67; }; struct MergeJoinThresholdSetting { @@ -1009,7 +1174,8 @@ struct MergeJoinThresholdSetting { static constexpr const char *Description = "The maximum number of rows on either table to choose a merge join"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "1000"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 68; }; struct NestedLoopJoinThresholdSetting { @@ -1019,7 +1185,8 @@ struct NestedLoopJoinThresholdSetting { "The maximum number of rows on either table to choose a nested loop join"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "5"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 69; }; struct OldImplicitCastingSetting { @@ -1028,7 +1195,8 @@ struct OldImplicitCastingSetting { static constexpr const char *Description = "Allow implicit casting to/from VARCHAR"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 70; }; struct OrderByNonIntegerLiteralSetting { @@ -1038,7 +1206,8 @@ struct OrderByNonIntegerLiteralSetting { "Allow ordering by non-integer literals - ordering by such literals has no effect."; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 71; }; struct OrderedAggregateThresholdSetting { @@ -1047,7 +1216,8 @@ struct OrderedAggregateThresholdSetting { static constexpr const char *Description = "The number of rows to accumulate before sorting, used for tuning"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "262144"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 72; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -1058,7 +1228,8 @@ struct PartitionedWriteFlushThresholdSetting { "The threshold in number of rows after which we flush a thread state when writing using PARTITION_BY"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "524288"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 73; }; struct PartitionedWriteMaxOpenFilesSetting { @@ -1068,7 +1239,8 @@ struct PartitionedWriteMaxOpenFilesSetting { "The maximum amount of files the system can keep open before flushing to disk when writing using PARTITION_BY"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "100"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 74; }; struct PasswordSetting { @@ -1076,9 +1248,9 @@ struct PasswordSetting { static constexpr const char *Name = "password"; static constexpr const char *Description = "The password to use. Ignored for legacy compatibility."; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 75; }; struct PerfectHtThresholdSetting { @@ -1087,7 +1259,8 @@ struct PerfectHtThresholdSetting { static constexpr const char *Description = "Threshold in bytes for when to use a perfect hash table"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "12"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 76; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -1097,9 +1270,10 @@ struct PinThreadsSetting { static constexpr const char *Description = "Whether to pin threads to cores (Linux only, default AUTO: on when there are more than 64 cores)"; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "auto"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 77; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct PivotFilterThresholdSetting { @@ -1109,7 +1283,8 @@ struct PivotFilterThresholdSetting { "The threshold to switch from using filtered aggregates to LIST with a dedicated pivot operator"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "20"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 78; }; struct PivotLimitSetting { @@ -1118,7 +1293,8 @@ struct PivotLimitSetting { static constexpr const char *Description = "The maximum number of pivot columns in a pivot statement"; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "100000"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 79; }; struct PreferRangeJoinsSetting { @@ -1127,7 +1303,8 @@ struct PreferRangeJoinsSetting { static constexpr const char *Description = "Force use of range joins with mixed predicates"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 80; }; struct PreserveIdentifierCaseSetting { @@ -1137,7 +1314,8 @@ struct PreserveIdentifierCaseSetting { "Whether or not to preserve the identifier case, instead of always lowercasing all non-quoted identifiers"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "true"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 81; }; struct PreserveInsertionOrderSetting { @@ -1148,7 +1326,8 @@ struct PreserveInsertionOrderSetting { "that do not contain ORDER BY clauses."; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "true"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 82; }; struct ProduceArrowStringViewSetting { @@ -1158,7 +1337,8 @@ struct ProduceArrowStringViewSetting { "Whether Arrow strings should be produced by DuckDB in Utf8View format instead of Utf8"; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "false"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 83; }; struct ProfileOutputSetting { @@ -1210,7 +1390,8 @@ struct ScalarSubqueryErrorOnMultipleRowsSetting { "When a scalar subquery returns multiple rows - return a random row instead of returning an error."; static constexpr const char *InputType = "BOOLEAN"; static constexpr const char *DefaultValue = "true"; - static constexpr SetScope DefaultScope = SetScope::SESSION; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::LOCAL_DEFAULT; + static constexpr idx_t SettingIndex = 84; }; struct SchedulerProcessPartialSetting { @@ -1219,9 +1400,13 @@ struct SchedulerProcessPartialSetting { static constexpr const char *Description = "Partially process tasks before rescheduling - allows for more scheduler fairness between separate queries"; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); +#ifdef DUCKDB_ALTERNATIVE_VERIFY + static constexpr const char *DefaultValue = "true"; +#else + static constexpr const char *DefaultValue = "false"; +#endif + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 85; }; struct SchemaSetting { @@ -1262,7 +1447,8 @@ struct StorageBlockPrefetchSetting { static constexpr const char *Description = "In which scenarios to use storage block prefetching"; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = "REMOTE_ONLY"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 86; static void OnSet(SettingCallbackInfo &info, Value &input); }; @@ -1302,9 +1488,10 @@ struct TempFileEncryptionSetting { static constexpr const char *Name = "temp_file_encryption"; static constexpr const char *Description = "Encrypt all temporary files if database is encrypted"; static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 87; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct ThreadsSetting { @@ -1322,9 +1509,9 @@ struct UsernameSetting { static constexpr const char *Name = "username"; static constexpr const char *Description = "The username to use. Ignored for legacy compatibility."; static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = ""; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 88; }; struct ValidateExternalFileCacheSetting { @@ -1335,19 +1522,42 @@ struct ValidateExternalFileCacheSetting { "remote cache entries), or NO_VALIDATION (disable cache validation)."; static constexpr const char *InputType = "VARCHAR"; static constexpr const char *DefaultValue = "VALIDATE_ALL"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 89; static void OnSet(SettingCallbackInfo &info, Value &input); }; -struct VariantMinimumShreddingSize { +struct VariantMinimumShreddingSizeSetting { using RETURN_TYPE = int64_t; static constexpr const char *Name = "variant_minimum_shredding_size"; static constexpr const char *Description = "Minimum size of a rowgroup to enable VARIANT shredding, or set to -1 " "to disable entirely. Defaults to 1/4th of a rowgroup"; static constexpr const char *InputType = "BIGINT"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "30000"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 90; +}; + +struct WalAutocheckpointEntriesSetting { + using RETURN_TYPE = idx_t; + static constexpr const char *Name = "wal_autocheckpoint_entries"; + static constexpr const char *Description = + "Trigger automatic checkpoint when WAL entry count reaches or exceeds N (0 = disabled)"; + static constexpr const char *InputType = "UBIGINT"; + static constexpr const char *DefaultValue = "0"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 91; +}; + +struct WarningsAsErrorsSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "warnings_as_errors"; + static constexpr const char *Description = "Escalate all warnings to errors."; + static constexpr const char *InputType = "BOOLEAN"; + static constexpr const char *DefaultValue = "false"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 92; + static void OnSet(SettingCallbackInfo &info, Value &input); }; struct WriteBufferRowGroupCountSetting { @@ -1357,7 +1567,8 @@ struct WriteBufferRowGroupCountSetting { "them together. Reducing this setting can reduce memory consumption."; static constexpr const char *InputType = "UBIGINT"; static constexpr const char *DefaultValue = "5"; - static constexpr SetScope DefaultScope = SetScope::GLOBAL; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_DEFAULT; + static constexpr idx_t SettingIndex = 93; }; struct ZstdMinStringLengthSetting { @@ -1366,9 +1577,13 @@ struct ZstdMinStringLengthSetting { static constexpr const char *Description = "The (average) length at which to enable ZSTD compression, defaults to 4096"; static constexpr const char *InputType = "UBIGINT"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); + static constexpr const char *DefaultValue = "4096"; + static constexpr SettingScopeTarget Scope = SettingScopeTarget::GLOBAL_ONLY; + static constexpr idx_t SettingIndex = 94; +}; + +struct GeneratedSettingInfo { + static constexpr idx_t MaxSettingIndex = 95; }; //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/main/user_settings.hpp b/src/duckdb/src/include/duckdb/main/user_settings.hpp new file mode 100644 index 000000000..37c4f91a4 --- /dev/null +++ b/src/duckdb/src/include/duckdb/main/user_settings.hpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/main/user_settings.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/common.hpp" +#include "duckdb/common/mutex.hpp" +#include "duckdb/common/types/value.hpp" +#include "duckdb/main/setting_info.hpp" +#include "duckdb/common/atomic.hpp" + +namespace duckdb { + +struct GenericSetting { + GenericSetting() : is_set(false) { + } + + bool is_set; + Value value; +}; + +struct UserSettingsMap { +public: + void SetUserSetting(idx_t setting_index, Value target_value); + void ClearSetting(idx_t setting_index); + bool IsSet(idx_t setting_index) const; + bool TryGetSetting(idx_t setting_index, Value &result_value) const; + +private: + vector settings; +}; + +#ifndef __MINGW32__ +struct GlobalUserSettings; + +struct CachedGlobalSettings { + CachedGlobalSettings(); + CachedGlobalSettings(const GlobalUserSettings &global_user_settings, idx_t version, UserSettingsMap settings); + + optional_ptr global_user_settings; + idx_t version; + UserSettingsMap settings; +}; +#endif + +struct GlobalUserSettings { +public: + GlobalUserSettings(); + // enable copy constructors + GlobalUserSettings(const GlobalUserSettings &other); + GlobalUserSettings &operator=(const GlobalUserSettings &); + + void SetUserSetting(idx_t setting_index, Value target_value); + void ClearSetting(idx_t setting_index); + bool IsSet(idx_t setting_index) const; + SettingLookupResult TryGetSetting(idx_t setting_index, Value &result_value) const; + bool HasExtensionOption(const string &name) const; + idx_t AddExtensionOption(const string &name, ExtensionOption extension_option); + case_insensitive_map_t GetExtensionSettings() const; + bool TryGetExtensionOption(const String &name, ExtensionOption &result) const; + +#ifndef __MINGW32__ + CachedGlobalSettings &GetSettings() const; +#endif + +private: + mutable mutex lock; + //! Database-global settings + UserSettingsMap settings_map; + //! Extra parameters that can be SET for loaded extensions + case_insensitive_map_t extension_parameters; + //! Current version of the settings - incremented when settings are modified + atomic settings_version; +}; + +struct LocalUserSettings { +public: + ~LocalUserSettings(); + + void SetUserSetting(idx_t setting_index, Value target_value); + void ClearSetting(idx_t setting_index); + bool IsSet(idx_t setting_index) const; + SettingLookupResult TryGetSetting(const GlobalUserSettings &global_settings, idx_t setting_index, + Value &result_value) const; + +private: + //! Client-local settings + UserSettingsMap settings_map; +}; +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/expression_heuristics.hpp b/src/duckdb/src/include/duckdb/optimizer/expression_heuristics.hpp index 49bb11e5b..0ae354854 100644 --- a/src/duckdb/src/include/duckdb/optimizer/expression_heuristics.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/expression_heuristics.hpp @@ -46,6 +46,6 @@ class ExpressionHeuristics : public LogicalOperatorVisitor { static idx_t ExpressionCost(BoundFunctionExpression &expr); static idx_t ExpressionCost(BoundOperatorExpression &expr, ExpressionType expr_type); static idx_t ExpressionCost(PhysicalType return_type, idx_t multiplier); - static idx_t Cost(TableFilter &filter); + static idx_t Cost(const TableFilter &filter); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp b/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp index 060274b36..b6a34facc 100644 --- a/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp @@ -57,7 +57,7 @@ class RelationStatisticsHelper { static constexpr double DEFAULT_SELECTIVITY = 0.2; public: - static idx_t InspectTableFilter(idx_t cardinality, idx_t column_index, TableFilter &filter, + static idx_t InspectTableFilter(idx_t cardinality, idx_t column_index, const TableFilter &filter, BaseStatistics &base_stats); // static idx_t InspectConjunctionOR(idx_t cardinality, idx_t column_index, ConjunctionOrFilter &filter, // BaseStatistics &base_stats); diff --git a/src/duckdb/src/include/duckdb/optimizer/optimizer_extension.hpp b/src/duckdb/src/include/duckdb/optimizer/optimizer_extension.hpp index d2202fcb1..4ea4b323d 100644 --- a/src/duckdb/src/include/duckdb/optimizer/optimizer_extension.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/optimizer_extension.hpp @@ -10,9 +10,10 @@ #include "duckdb/common/common.hpp" #include "duckdb/planner/logical_operator.hpp" +#include "duckdb/main/extension_callback_manager.hpp" namespace duckdb { - +struct DBConfig; class Optimizer; class ClientContext; @@ -44,6 +45,11 @@ class OptimizerExtension { //! Additional optimizer info passed to the optimize functions shared_ptr optimizer_info; + + static void Register(DBConfig &config, OptimizerExtension extension); + static ExtensionCallbackIteratorHelper Iterate(ClientContext &context) { + return ExtensionCallbackManager::Get(context).OptimizerExtensions(); + } }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/remove_unused_columns.hpp b/src/duckdb/src/include/duckdb/optimizer/remove_unused_columns.hpp index 4d02f224c..a4fad42ac 100644 --- a/src/duckdb/src/include/duckdb/optimizer/remove_unused_columns.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/remove_unused_columns.hpp @@ -89,13 +89,16 @@ class BaseColumnPruner : public LogicalOperatorVisitor { //! ret: The amount of bindings created idx_t ReplaceBinding(ColumnBinding current_binding, ColumnBinding new_binding); - bool HandleStructExtract(unique_ptr *expression, - optional_ptr> cast_expression = nullptr); - - bool HandleStructExtractRecursive(unique_ptr &expr, optional_ptr &colref, - vector &indexes, vector &expressions); + bool HandleExtractExpression(unique_ptr *expression, + optional_ptr> cast_expression = nullptr); + + bool HandleStructExtract(unique_ptr &expr, optional_ptr &colref, + reference &path_ref, vector &expressions); + bool HandleVariantExtract(unique_ptr &expr, optional_ptr &colref, + reference &path_ref, vector &expressions); + bool HandleExtractRecursive(unique_ptr &expr, optional_ptr &colref, + reference &path_ref, vector &expressions); void SetMode(BaseColumnPrunerMode mode); - bool HandleStructPack(Expression &expr); BaseColumnPrunerMode GetMode() const; private: @@ -134,6 +137,6 @@ class RemoveUnusedColumns : public BaseColumnPruner { void RewriteExpressions(LogicalProjection &proj, idx_t expression_count); void WritePushdownExtractColumns( const ColumnBinding &binding, ReferencedColumn &col, idx_t original_idx, const LogicalType &column_type, - const std::function cast_type)> &callback); + const std::function cast_type)> &callback); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp b/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp index 1ec4acaa9..08340b0a5 100644 --- a/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp @@ -81,7 +81,7 @@ class StatisticsPropagator { //! Run a comparison between the statistics and the table filter; returns the prune result FilterPropagateResult PropagateTableFilter(ColumnBinding stats_binding, BaseStatistics &stats, TableFilter &filter); //! Update filter statistics from a TableFilter - void UpdateFilterStatistics(BaseStatistics &input, TableFilter &filter); + void UpdateFilterStatistics(BaseStatistics &input, const TableFilter &filter); //! Add cardinalities together (i.e. new max is stats.max + new_stats.max): used for union void AddCardinalities(unique_ptr &stats, NodeStatistics &new_stats); diff --git a/src/duckdb/src/include/duckdb/optimizer/topn_window_elimination.hpp b/src/duckdb/src/include/duckdb/optimizer/topn_window_elimination.hpp index 0fb5ba00c..2a52f432b 100644 --- a/src/duckdb/src/include/duckdb/optimizer/topn_window_elimination.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/topn_window_elimination.hpp @@ -11,6 +11,7 @@ #include "duckdb/main/client_context.hpp" #include "duckdb/optimizer/column_binding_replacer.hpp" #include "duckdb/optimizer/remove_unused_columns.hpp" +#include "duckdb/optimizer/optimizer.hpp" namespace duckdb { diff --git a/src/duckdb/src/include/duckdb/optimizer/window_self_join.hpp b/src/duckdb/src/include/duckdb/optimizer/window_self_join.hpp index dc9c0a300..bac7e9976 100644 --- a/src/duckdb/src/include/duckdb/optimizer/window_self_join.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/window_self_join.hpp @@ -21,6 +21,7 @@ class WindowSelfJoinOptimizer { unique_ptr Optimize(unique_ptr op); private: + bool CanOptimize(const BoundWindowExpression &w_expr, const BoundWindowExpression &w_expr0) const; unique_ptr OptimizeInternal(unique_ptr op, ColumnBindingReplacer &replacer); Optimizer &optimizer; diff --git a/src/duckdb/src/include/duckdb/parallel/pipeline.hpp b/src/duckdb/src/include/duckdb/parallel/pipeline.hpp index 45e603467..0d8a665a5 100644 --- a/src/duckdb/src/include/duckdb/parallel/pipeline.hpp +++ b/src/duckdb/src/include/duckdb/parallel/pipeline.hpp @@ -86,6 +86,7 @@ class Pipeline : public enable_shared_from_this { ClientContext &GetClientContext(); void AddDependency(shared_ptr &pipeline); + vector> GetDependencies() const; void Ready(); void Reset(); diff --git a/src/duckdb/src/include/duckdb/parallel/task_scheduler.hpp b/src/duckdb/src/include/duckdb/parallel/task_scheduler.hpp index 315c56e9e..f734ab214 100644 --- a/src/duckdb/src/include/duckdb/parallel/task_scheduler.hpp +++ b/src/duckdb/src/include/duckdb/parallel/task_scheduler.hpp @@ -90,7 +90,7 @@ class TaskScheduler { static idx_t GetEstimatedCPUId(); private: - void RelaunchThreadsInternal(int32_t n); + void RelaunchThreadsInternal(int32_t n, bool destroy); private: DatabaseInstance &db; diff --git a/src/duckdb/src/include/duckdb/parser/expression/lambda_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/lambda_expression.hpp index 276edf418..08c02f835 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/lambda_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/lambda_expression.hpp @@ -11,10 +11,10 @@ #include "duckdb/common/unordered_set.hpp" #include "duckdb/common/vector.hpp" #include "duckdb/parser/parsed_expression.hpp" +#include "duckdb/common/enums/lambda_syntax.hpp" namespace duckdb { -enum class LambdaSyntax : uint8_t { DEFAULT = 0, ENABLE_SINGLE_ARROW = 1, DISABLE_SINGLE_ARROW = 2 }; enum class LambdaSyntaxType : uint8_t { SINGLE_ARROW_STORAGE = 0, SINGLE_ARROW = 1, LAMBDA_KEYWORD = 2 }; //! DuckDB 1.3. introduced a new lambda syntax: lambda x, y: x + y. diff --git a/src/duckdb/src/include/duckdb/parser/expression/list.hpp b/src/duckdb/src/include/duckdb/parser/expression/list.hpp index 0114a55a2..c6d84ec4b 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/list.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/list.hpp @@ -17,3 +17,4 @@ #include "duckdb/parser/expression/star_expression.hpp" #include "duckdb/parser/expression/subquery_expression.hpp" #include "duckdb/parser/expression/window_expression.hpp" +#include "duckdb/parser/expression/type_expression.hpp" diff --git a/src/duckdb/src/include/duckdb/parser/expression/type_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/type_expression.hpp new file mode 100644 index 000000000..e26e2fc4e --- /dev/null +++ b/src/duckdb/src/include/duckdb/parser/expression/type_expression.hpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/parser/expression/type_expression.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/vector.hpp" +#include "duckdb/parser/parsed_expression.hpp" +#include "duckdb/parser/keyword_helper.hpp" + +namespace duckdb { + +class TypeExpression : public ParsedExpression { +public: + static constexpr const ExpressionClass TYPE = ExpressionClass::TYPE; + + TypeExpression(string catalog, string schema, string type_name, vector> children); + TypeExpression(string type_name, vector> children); + +public: + const string &GetTypeName() const { + return type_name; + } + const string &GetSchema() const { + return schema; + } + const string &GetCatalog() const { + return catalog; + } + const vector> &GetChildren() const { + return children; + } + vector> &GetChildren() { + return children; + } + +public: + string ToString() const override; + + unique_ptr Copy() const override; + + static bool Equal(const TypeExpression &a, const TypeExpression &b); + hash_t Hash() const override; + + void Serialize(Serializer &serializer) const override; + static unique_ptr Deserialize(Deserializer &deserializer); + + void Verify() const override; + +private: + TypeExpression(); + + //! Qualified name parts + string catalog; + string schema; + string type_name; + + //! Children of the type expression (e.g. type parameters) + vector> children; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/keyword_helper.hpp b/src/duckdb/src/include/duckdb/parser/keyword_helper.hpp index d53951105..5a621321b 100644 --- a/src/duckdb/src/include/duckdb/parser/keyword_helper.hpp +++ b/src/duckdb/src/include/duckdb/parser/keyword_helper.hpp @@ -16,20 +16,22 @@ namespace duckdb { class KeywordHelper { public: //! Returns true if the given text matches a keyword of the parser - static bool IsKeyword(const string &text); + static bool IsKeyword(const string &text, KeywordCategory category = KeywordCategory::KEYWORD_NONE); static KeywordCategory KeywordCategoryType(const string &text); static string EscapeQuotes(const string &text, char quote = '"'); //! Returns true if the given string needs to be quoted when written as an identifier - static bool RequiresQuotes(const string &text, bool allow_caps = true); + static bool RequiresQuotes(const string &text, bool allow_caps = true, + KeywordCategory category = KeywordCategory::KEYWORD_NONE); //! Writes a string that is quoted static string WriteQuoted(const string &text, char quote = '\''); //! Writes a string that is optionally quoted + escaped so it can be used as an identifier - static string WriteOptionallyQuoted(const string &text, char quote = '"', bool allow_caps = true); + static string WriteOptionallyQuoted(const string &text, char quote = '"', bool allow_caps = true, + KeywordCategory category = KeywordCategory::KEYWORD_NONE); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_info.hpp index 1408d6e28..0730f7642 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_info.hpp @@ -84,7 +84,9 @@ enum class AlterTableType : uint8_t { SET_SORTED_BY = 13, ADD_FIELD = 14, REMOVE_FIELD = 15, - RENAME_FIELD = 16 + RENAME_FIELD = 16, + SET_TABLE_OPTIONS = 17, + RESET_TABLE_OPTIONS = 18, }; struct AlterTableInfo : public AlterInfo { @@ -493,4 +495,44 @@ struct SetSortedByInfo : public AlterTableInfo { SetSortedByInfo(); }; +//===--------------------------------------------------------------------===// +// SetOptionsInfo +//===--------------------------------------------------------------------===// +struct SetTableOptionsInfo : public AlterTableInfo { + SetTableOptionsInfo(AlterEntryData data, case_insensitive_map_t> table_options); + ~SetTableOptionsInfo() override; + + case_insensitive_map_t> table_options; + +public: + unique_ptr Copy() const override; + string ToString() const override; + + void Serialize(Serializer &serializer) const override; + static unique_ptr Deserialize(Deserializer &deserializer); + +private: + SetTableOptionsInfo(); +}; + +//===--------------------------------------------------------------------===// +// ResetOptionsInfo +//===--------------------------------------------------------------------===// +struct ResetTableOptionsInfo : public AlterTableInfo { + ResetTableOptionsInfo(AlterEntryData data, case_insensitive_set_t table_options); + ~ResetTableOptionsInfo() override; + + case_insensitive_set_t table_options; + +public: + unique_ptr Copy() const override; + string ToString() const override; + + void Serialize(Serializer &serializer) const override; + static unique_ptr Deserialize(Deserializer &deserializer); + +private: + ResetTableOptionsInfo(); +}; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_coordinate_system_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_coordinate_system_info.hpp new file mode 100644 index 000000000..19d2786ac --- /dev/null +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_coordinate_system_info.hpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/parser/parsed_data/create_collation_info.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/parser/parsed_data/create_info.hpp" + +namespace duckdb { + +struct CreateCoordinateSystemInfo : public CreateInfo { + DUCKDB_API CreateCoordinateSystemInfo(string name_p, string authority, string code, string projjson, + string wkt2_2019); + + //! The name of the coordinate system + //! This is typically in the format "AUTH:CODE", e.g. "OGC:CRS84" + string name; + + //! The authority identifier of the coordinate system (e.g. "EPSG") + string authority; + + //! The code identifier of the coordinate system (e.g. "4326") + string code; + + //! The PROJJSON definition of the coordinate system + string projjson_definition; + + //! The WKT2:2019 definition of the coordinate system + string wkt2_2019_definition; + +public: + unique_ptr Copy() const override; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_secret_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_secret_info.hpp index fe345d6e8..aeda83e0c 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/create_secret_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_secret_info.hpp @@ -23,8 +23,6 @@ struct CreateSecretInfo : public CreateInfo { // NOLINT: work-around bug in clan explicit CreateSecretInfo(OnCreateConflict on_conflict, SecretPersistType persist_type); ~CreateSecretInfo() override; - //! How to handle conflict - OnCreateConflict on_conflict; //! Whether the secret can be persisted SecretPersistType persist_type; //! The type of secret diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_table_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_table_info.hpp index 84423dc59..ebbd2a6bf 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/create_table_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_table_info.hpp @@ -29,6 +29,12 @@ struct CreateTableInfo : public CreateInfo { vector> constraints; //! CREATE TABLE as QUERY unique_ptr query; + //! Table Partition definitions + vector> partition_keys; + //! Table Sort definitions + vector> sort_keys; + //! Extra Table options if any + case_insensitive_map_t> options; public: DUCKDB_API unique_ptr Copy() const override; @@ -36,6 +42,7 @@ struct CreateTableInfo : public CreateInfo { DUCKDB_API void Serialize(Serializer &serializer) const override; DUCKDB_API static unique_ptr Deserialize(Deserializer &deserializer); + string ExtraOptionsToString() const; string ToString() const override; }; diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_type_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_type_info.hpp index 2c4eb983f..8d25b626a 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/create_type_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_type_info.hpp @@ -13,14 +13,42 @@ namespace duckdb { +class TypeArgument { +public: + TypeArgument(string name_p, Value value_p) : name(std::move(name_p)), value(std::move(value_p)) { + } + const string &GetName() const { + return name; + } + const Value &GetValue() const { + return value; + } + bool HasName() const { + return !name.empty(); + } + bool IsNamed(const char *name_to_check) const { + return StringUtil::CIEquals(name, name_to_check); + } + bool IsNotNull() const { + return !value.IsNull(); + } + const LogicalType &GetType() const { + return value.type(); + } + +private: + string name; + Value value; +}; + struct BindLogicalTypeInput { - ClientContext &context; + optional_ptr context; const LogicalType &base_type; - const vector &modifiers; + const vector &modifiers; }; //! The type to bind type modifiers to a type -typedef LogicalType (*bind_logical_type_function_t)(const BindLogicalTypeInput &input); +typedef LogicalType (*bind_logical_type_function_t)(BindLogicalTypeInput &input); struct CreateTypeInfo : public CreateInfo { CreateTypeInfo(); diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_view_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_view_info.hpp index f45f9ecb5..cb005325e 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/create_view_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_view_info.hpp @@ -30,7 +30,7 @@ struct CreateViewInfo : public CreateInfo { //! Names of the query vector names; //! Comments on columns of the query. Note: vector can be empty when no comments are set - vector column_comments; + unordered_map column_comments_map; //! The SelectStatement of the view unique_ptr query; @@ -49,6 +49,11 @@ struct CreateViewInfo : public CreateInfo { DUCKDB_API static unique_ptr Deserialize(Deserializer &deserializer); string ToString() const override; + +private: + CreateViewInfo(vector names, vector comments, unordered_map column_comments); + + vector GetColumnCommentsList() const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parser_extension.hpp b/src/duckdb/src/include/duckdb/parser/parser_extension.hpp index cf264adc7..bffe59695 100644 --- a/src/duckdb/src/include/duckdb/parser/parser_extension.hpp +++ b/src/duckdb/src/include/duckdb/parser/parser_extension.hpp @@ -8,12 +8,14 @@ #pragma once +#include "duckdb/parser/parser_options.hpp" #include "duckdb/common/common.hpp" #include "duckdb/common/enums/statement_type.hpp" #include "duckdb/function/table_function.hpp" #include "duckdb/parser/sql_statement.hpp" namespace duckdb { +struct DBConfig; //! The ParserExtensionInfo holds static information relevant to the parser extension //! It is made available in the parse_function, and will be kept alive as long as the database system is kept alive @@ -94,7 +96,8 @@ struct ParserOverrideResult { ErrorData error; }; -typedef ParserOverrideResult (*parser_override_function_t)(ParserExtensionInfo *info, const string &query); +typedef ParserOverrideResult (*parser_override_function_t)(ParserExtensionInfo *info, const string &query, + ParserOptions &options); //===--------------------------------------------------------------------===// // ParserExtension @@ -114,6 +117,8 @@ class ParserExtension { //! Additional parser info passed to the parse function shared_ptr parser_info; + + static void Register(DBConfig &config, ParserExtension extension); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parser_options.hpp b/src/duckdb/src/include/duckdb/parser/parser_options.hpp index d9a42632a..2d8227aca 100644 --- a/src/duckdb/src/include/duckdb/parser/parser_options.hpp +++ b/src/duckdb/src/include/duckdb/parser/parser_options.hpp @@ -9,16 +9,19 @@ #pragma once #include "duckdb/common/common.hpp" +#include "duckdb/common/enums/allow_parser_override.hpp" +#include "duckdb/common/optional_ptr.hpp" namespace duckdb { +class ExtensionCallbackManager; class ParserExtension; struct ParserOptions { bool preserve_identifier_case = true; bool integer_division = false; idx_t max_expression_depth = 1000; - const vector *extensions = nullptr; - string parser_override_setting = "default"; + optional_ptr extensions; + AllowParserOverride parser_override_setting = AllowParserOverride::DEFAULT_OVERRIDE; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/query_node.hpp b/src/duckdb/src/include/duckdb/parser/query_node.hpp index 4981e8afc..98f085523 100644 --- a/src/duckdb/src/include/duckdb/parser/query_node.hpp +++ b/src/duckdb/src/include/duckdb/parser/query_node.hpp @@ -41,7 +41,6 @@ class CommonTableExpressionMap { CommonTableExpressionMap Copy() const; void Serialize(Serializer &serializer) const; - // static void Deserialize(Deserializer &deserializer, CommonTableExpressionMap &ret); static CommonTableExpressionMap Deserialize(Deserializer &deserializer); }; diff --git a/src/duckdb/src/include/duckdb/parser/statement/update_statement.hpp b/src/duckdb/src/include/duckdb/parser/statement/update_statement.hpp index fb1abb4d6..2af2ae2e8 100644 --- a/src/duckdb/src/include/duckdb/parser/statement/update_statement.hpp +++ b/src/duckdb/src/include/duckdb/parser/statement/update_statement.hpp @@ -50,6 +50,8 @@ class UpdateStatement : public SQLStatement { unique_ptr set_info; //! CTEs CommonTableExpressionMap cte_map; + //! bind the same way as `ALTER TABLE` expressions, (where the catalog the table is in is preferred) + bool prioritize_table_when_binding; protected: UpdateStatement(const UpdateStatement &other); diff --git a/src/duckdb/src/include/duckdb/parser/tableref/expressionlistref.hpp b/src/duckdb/src/include/duckdb/parser/tableref/expressionlistref.hpp index 7d0bd86e1..a38bd422b 100644 --- a/src/duckdb/src/include/duckdb/parser/tableref/expressionlistref.hpp +++ b/src/duckdb/src/include/duckdb/parser/tableref/expressionlistref.hpp @@ -14,7 +14,9 @@ #include "duckdb/common/vector.hpp" namespace duckdb { -//! Represents an expression list as generated by a VALUES statement + +//! A table reference that consists of a list of expressions. +//! The expression list is generated by, e.g., a VALUES statement. class ExpressionListRef : public TableRef { public: static constexpr const TableReferenceType TYPE = TableReferenceType::EXPRESSION_LIST; @@ -23,11 +25,11 @@ class ExpressionListRef : public TableRef { ExpressionListRef() : TableRef(TableReferenceType::EXPRESSION_LIST) { } - //! Value list, only used for VALUES statement + //! Value list like in a VALUES statement. vector>> values; - //! Expected SQL types + //! Expected table types. vector expected_types; - //! The set of expected names + //! Expected table names. vector expected_names; public: diff --git a/src/duckdb/src/include/duckdb/parser/tableref/showref.hpp b/src/duckdb/src/include/duckdb/parser/tableref/showref.hpp index 163bf66ad..78a1e1266 100644 --- a/src/duckdb/src/include/duckdb/parser/tableref/showref.hpp +++ b/src/duckdb/src/include/duckdb/parser/tableref/showref.hpp @@ -14,7 +14,7 @@ namespace duckdb { -enum class ShowType : uint8_t { SUMMARY, DESCRIBE, SHOW_FROM }; +enum class ShowType : uint8_t { SUMMARY, DESCRIBE, SHOW_FROM, SHOW_UNQUALIFIED }; //! Represents a SHOW/DESCRIBE/SUMMARIZE statement class ShowRef : public TableRef { diff --git a/src/duckdb/src/include/duckdb/parser/transformer.hpp b/src/duckdb/src/include/duckdb/parser/transformer.hpp index 8a8ba2ecb..460755566 100644 --- a/src/duckdb/src/include/duckdb/parser/transformer.hpp +++ b/src/duckdb/src/include/duckdb/parser/transformer.hpp @@ -156,6 +156,8 @@ class Transformer { unique_ptr TransformCopy(duckdb_libpgquery::PGCopyStmt &stmt); void TransformCopyOptions(CopyInfo &info, optional_ptr options); void TransformCreateSecretOptions(CreateSecretInfo &info, optional_ptr options); + void TransformTableOptions(case_insensitive_map_t> &info, + optional_ptr options, bool throw_if_value = false); //! Transform a Postgres duckdb_libpgquery::T_PGTransactionStmt node into a TransactionStatement unique_ptr TransformTransaction(duckdb_libpgquery::PGTransactionStmt &stmt); //! Transform a Postgres T_DeleteStatement node into a DeleteStatement @@ -191,8 +193,6 @@ class Transformer { unique_ptr CreatePivotStatement(unique_ptr statement); PivotColumn TransformPivotColumn(duckdb_libpgquery::PGPivot &pivot, bool is_pivot); vector TransformPivotList(duckdb_libpgquery::PGList &list, bool is_pivot); - static bool TransformPivotInList(unique_ptr &expr, PivotColumnEntry &entry, - bool root_entry = true); unique_ptr TransformMergeInto(duckdb_libpgquery::PGMergeIntoStmt &stmt); unique_ptr TransformMergeIntoAction(duckdb_libpgquery::PGMatchAction &action); @@ -308,7 +308,6 @@ class Transformer { unique_ptr TransformUnaryOperator(const string &op, unique_ptr child); unique_ptr TransformBinaryOperator(string op, unique_ptr left, unique_ptr right); - static bool ConstructConstantFromExpression(const ParsedExpression &expr, Value &value); //===--------------------------------------------------------------------===// // TableRef transform //===--------------------------------------------------------------------===// @@ -336,13 +335,11 @@ class Transformer { QualifiedName TransformQualifiedName(duckdb_libpgquery::PGRangeVar &root); //! Transform a Postgres TypeName string into a LogicalType (non-LIST types) - LogicalType TransformTypeNameInternal(duckdb_libpgquery::PGTypeName &name); + unique_ptr TransformTypeExpressionInternal(duckdb_libpgquery::PGTypeName &name); + unique_ptr TransformTypeExpression(duckdb_libpgquery::PGTypeName &name); //! Transform a Postgres TypeName string into a LogicalType LogicalType TransformTypeName(duckdb_libpgquery::PGTypeName &name); - //! Transform a list of type modifiers into a list of values - vector TransformTypeModifiers(duckdb_libpgquery::PGTypeName &name); - //! Transform a Postgres GROUP BY expression into a list of Expression bool TransformGroupBy(optional_ptr group, SelectNode &result); void TransformGroupByNode(duckdb_libpgquery::PGNode &n, GroupingExpressionMap &map, SelectNode &result, diff --git a/src/duckdb/src/include/duckdb/planner/bind_context.hpp b/src/duckdb/src/include/duckdb/planner/bind_context.hpp index db5b52c78..7b4d8d567 100644 --- a/src/duckdb/src/include/duckdb/planner/bind_context.hpp +++ b/src/duckdb/src/include/duckdb/planner/bind_context.hpp @@ -46,7 +46,8 @@ class BindContext { public: //! Given a column name, find the matching table it belongs to. Throws an //! exception if no table has a column of the given name. - optional_ptr GetMatchingBinding(const string &column_name); + optional_ptr GetMatchingBinding(const string &column_name, + QueryErrorContext context = QueryErrorContext()); //! Like GetMatchingBinding, but instead of throwing an error if multiple tables have the same binding it will //! return a list of all the matching ones vector> GetMatchingBindings(const string &column_name); diff --git a/src/duckdb/src/include/duckdb/planner/binder.hpp b/src/duckdb/src/include/duckdb/planner/binder.hpp index 523ba484a..7e3d6f8c8 100644 --- a/src/duckdb/src/include/duckdb/planner/binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/binder.hpp @@ -242,6 +242,11 @@ class Binder : public enable_shared_from_this { void SetCatalogLookupCallback(catalog_entry_callback_t callback); void BindCreateViewInfo(CreateViewInfo &base); + static void BindView(ClientContext &context, const SelectStatement &stmt, const string &catalog_name, + const string &schema_name, optional_ptr dependencies, + const vector &aliases, vector &result_types, + vector &result_names); + void SearchSchema(CreateInfo &info); SchemaCatalogEntry &BindSchema(CreateInfo &info); SchemaCatalogEntry &BindCreateFunctionInfo(CreateInfo &info); @@ -279,17 +284,19 @@ class Binder : public enable_shared_from_this { unique_ptr BindUpdateSet(LogicalOperator &op, unique_ptr root, UpdateSetInfo &set_info, TableCatalogEntry &table, - vector &columns); + vector &columns, + bool prioritize_table_when_binding = false); void BindUpdateSet(idx_t proj_index, unique_ptr &root, UpdateSetInfo &set_info, TableCatalogEntry &table, vector &columns, vector> &update_expressions, - vector> &projection_expressions); + vector> &projection_expressions, + bool prioritize_table_when_binding = false); void BindVacuumTable(LogicalVacuum &vacuum, unique_ptr &root); static void BindSchemaOrCatalog(ClientContext &context, string &catalog, string &schema); - void BindLogicalType(LogicalType &type, optional_ptr catalog = nullptr, - const string &schema = INVALID_SCHEMA); + + void BindLogicalType(LogicalType &type); optional_ptr GetMatchingBinding(const string &table_name, const string &column_name, ErrorData &error); optional_ptr GetMatchingBinding(const string &schema_name, const string &table_name, @@ -321,6 +328,8 @@ class Binder : public enable_shared_from_this { unique_ptr UnionOperators(vector> nodes); + void SetSearchPath(Catalog &catalog, const string &schema); + private: //! The parent binder (if any) shared_ptr parent; @@ -505,7 +514,7 @@ class Binder : public enable_shared_from_this { vector GetSearchPath(Catalog &catalog, const string &schema_name); - LogicalType BindLogicalTypeInternal(const LogicalType &type, optional_ptr catalog, const string &schema); + LogicalType BindLogicalTypeInternal(const unique_ptr &type_expr); BoundStatement BindSelectNode(SelectNode &statement, BoundStatement from_table); @@ -538,6 +547,8 @@ class Binder : public enable_shared_from_this { BoundCTEData PrepareCTE(const string &ctename, CommonTableExpressionInfo &statement); BoundStatement FinishCTE(BoundCTEData &bound_cte, BoundStatement child_data); + shared_ptr CreateBinderWithSearchPath(const string &catalog_name, const string &schema_name); + private: Binder(ClientContext &context, shared_ptr parent, BinderType binder_type); }; diff --git a/src/duckdb/src/include/duckdb/planner/expression_binder.hpp b/src/duckdb/src/include/duckdb/planner/expression_binder.hpp index 3232c4d99..a60c8b375 100644 --- a/src/duckdb/src/include/duckdb/planner/expression_binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression_binder.hpp @@ -14,6 +14,7 @@ #include "duckdb/common/exception/binder_exception.hpp" #include "duckdb/parser/expression/bound_expression.hpp" #include "duckdb/parser/expression/lambdaref_expression.hpp" +#include "duckdb/parser/expression/type_expression.hpp" #include "duckdb/parser/parsed_expression.hpp" #include "duckdb/parser/tokens.hpp" #include "duckdb/planner/expression.hpp" @@ -115,7 +116,8 @@ class ExpressionBinder { BindResult BindQualifiedColumnName(ColumnRefExpression &colref, const string &table_name); //! Returns a qualified column reference from a column name - unique_ptr QualifyColumnName(const string &column_name, ErrorData &error); + unique_ptr QualifyColumnName(const ParsedExpression &expr, const string &column_name, + ErrorData &error); //! Returns a qualified column reference from a column reference with column_names.size() > 2 unique_ptr QualifyColumnNameWithManyDots(ColumnRefExpression &col_ref, ErrorData &error); //! Returns a qualified column reference from a column reference @@ -180,6 +182,7 @@ class ExpressionBinder { BindResult BindExpression(ConjunctionExpression &expr, idx_t depth); BindResult BindExpression(ConstantExpression &expr, idx_t depth); BindResult BindExpression(FunctionExpression &expr, idx_t depth, unique_ptr &expr_ptr); + BindResult BindExpression(TypeExpression &expr, idx_t depth); BindResult BindExpression(LambdaExpression &expr, idx_t depth, const vector &function_child_types, optional_ptr bind_lambda_function); diff --git a/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp b/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp index b111cc368..02c70229a 100644 --- a/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp @@ -27,6 +27,8 @@ class HavingBinder : public BaseSelectBinder { unique_ptr QualifyColumnName(ColumnRefExpression &col_ref, ErrorData &error) override; + bool DoesColumnAliasExist(const ColumnRefExpression &colref) override; + private: ColumnAliasBinder column_alias_binder; AggregateHandling aggregate_handling; diff --git a/src/duckdb/src/include/duckdb/planner/expression_binder/table_function_binder.hpp b/src/duckdb/src/include/duckdb/planner/expression_binder/table_function_binder.hpp index cc20dd5ed..a86c2ed45 100644 --- a/src/duckdb/src/include/duckdb/planner/expression_binder/table_function_binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression_binder/table_function_binder.hpp @@ -18,6 +18,14 @@ class TableFunctionBinder : public ExpressionBinder { TableFunctionBinder(Binder &binder, ClientContext &context, string table_function_name = string(), string clause = "Table function"); +public: + void DisableSQLValueFunctions() { + accept_sql_value_functions = false; + } + void EnableSQLValueFunctions() { + accept_sql_value_functions = true; + } + protected: BindResult BindLambdaReference(LambdaRefExpression &expr, idx_t depth); BindResult BindColumnReference(unique_ptr &expr, idx_t depth, bool root_expression); @@ -28,6 +36,8 @@ class TableFunctionBinder : public ExpressionBinder { private: string table_function_name; string clause; + //! Whether sql_value_functions (GetSQLValueFunctionName) are considered when binding column refs + bool accept_sql_value_functions = true; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/extension_callback.hpp b/src/duckdb/src/include/duckdb/planner/extension_callback.hpp index 389f8f257..d457019bf 100644 --- a/src/duckdb/src/include/duckdb/planner/extension_callback.hpp +++ b/src/duckdb/src/include/duckdb/planner/extension_callback.hpp @@ -9,8 +9,10 @@ #pragma once #include "duckdb/common/common.hpp" +#include "duckdb/main/extension_callback_manager.hpp" namespace duckdb { +struct DBConfig; class ClientContext; class DatabaseInstance; class ErrorData; @@ -35,6 +37,14 @@ class ExtensionCallback { //! Called after an extension fails to load loading virtual void OnExtensionLoadFail(DatabaseInstance &db, const string &name, const ErrorData &error) { } + + static void Register(DBConfig &config, shared_ptr extension); + static ExtensionCallbackIteratorHelper> Iterate(ClientContext &context) { + return ExtensionCallbackManager::Get(context).ExtensionCallbacks(); + } + static ExtensionCallbackIteratorHelper> Iterate(DatabaseInstance &db) { + return ExtensionCallbackManager::Get(db).ExtensionCallbacks(); + } }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/filter/dynamic_filter.hpp b/src/duckdb/src/include/duckdb/planner/filter/dynamic_filter.hpp index 46cb9b5de..2d8c6bc79 100644 --- a/src/duckdb/src/include/duckdb/planner/filter/dynamic_filter.hpp +++ b/src/duckdb/src/include/duckdb/planner/filter/dynamic_filter.hpp @@ -13,13 +13,14 @@ #include "duckdb/common/types/value.hpp" #include "duckdb/common/enums/expression_type.hpp" #include "duckdb/planner/filter/constant_filter.hpp" +#include "duckdb/common/atomic.hpp" namespace duckdb { struct DynamicFilterData { mutex lock; unique_ptr filter; - bool initialized = false; + atomic initialized = {false}; void SetValue(Value val); void Reset(); diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp index 308edcc45..f6990fe01 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp @@ -60,6 +60,8 @@ class LogicalGet : public LogicalOperator { shared_ptr dynamic_filters; //! Information for WITH ORDINALITY optional_idx ordinality_idx; + //! Row group order options (if set) + unique_ptr row_group_order_options; string GetName() const override; InsertionOrderPreservingMap ParamsToString() const override; @@ -81,6 +83,7 @@ class LogicalGet : public LogicalOperator { vector GetColumnBindings() override; idx_t EstimateCardinality(ClientContext &context) override; bool TryGetStorageIndex(const ColumnIndex &column_index, StorageIndex &out_index) const; + void SetScanOrder(unique_ptr options); vector GetTableIndex() const override; //! Skips the serialization check in VerifyPlan diff --git a/src/duckdb/src/include/duckdb/planner/operator_extension.hpp b/src/duckdb/src/include/duckdb/planner/operator_extension.hpp index b14b640d1..35668580b 100644 --- a/src/duckdb/src/include/duckdb/planner/operator_extension.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator_extension.hpp @@ -11,9 +11,12 @@ #include "duckdb/common/common.hpp" #include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/planner/binder.hpp" +#include "duckdb/main/extension_callback_manager.hpp" namespace duckdb { +struct DBConfig; + //! The OperatorExtensionInfo holds static information relevant to the operator extension struct OperatorExtensionInfo { virtual ~OperatorExtensionInfo() { @@ -38,6 +41,11 @@ class OperatorExtension { virtual ~OperatorExtension() { } + + static void Register(DBConfig &config, shared_ptr extension); + static ExtensionCallbackIteratorHelper> Iterate(ClientContext &context) { + return ExtensionCallbackManager::Get(context).OperatorExtensions(); + } }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/planner_extension.hpp b/src/duckdb/src/include/duckdb/planner/planner_extension.hpp new file mode 100644 index 000000000..669ddbde6 --- /dev/null +++ b/src/duckdb/src/include/duckdb/planner/planner_extension.hpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/planner/planner_extension.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/common.hpp" +#include "duckdb/planner/bound_statement.hpp" +#include "duckdb/main/extension_callback_manager.hpp" + +namespace duckdb { +struct DBConfig; +class Binder; +class ClientContext; + +//! The PlannerExtensionInfo holds static information relevant to the planner extension +struct PlannerExtensionInfo { + virtual ~PlannerExtensionInfo() { + } +}; + +struct PlannerExtensionInput { + ClientContext &context; + Binder &binder; + optional_ptr info; +}; + +//! The post_bind function runs after binding succeeds, allowing modification of the bound statement +typedef void (*post_bind_function_t)(PlannerExtensionInput &input, BoundStatement &statement); + +class PlannerExtension { +public: + //! The post-bind function of the planner extension. + //! Takes a bound statement as input, which it can modify in place. + //! This runs after the binder has successfully bound the statement, + //! allowing modification of the plan and result types. + post_bind_function_t post_bind_function = nullptr; + + //! Additional planner info passed to the functions + shared_ptr planner_info; + + static void Register(DBConfig &config, PlannerExtension extension); + static ExtensionCallbackIteratorHelper Iterate(ClientContext &context) { + return ExtensionCallbackManager::Get(context).PlannerExtensions(); + } +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/block_manager.hpp b/src/duckdb/src/include/duckdb/storage/block_manager.hpp index 695b6aed9..1b7828bac 100644 --- a/src/duckdb/src/include/duckdb/storage/block_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/block_manager.hpp @@ -26,8 +26,8 @@ class MetadataManager; enum class ConvertToPersistentMode { DESTRUCTIVE, THREAD_SAFE }; -//! BlockManager is an abstract representation to manage blocks on DuckDB. When writing or reading blocks, the -//! BlockManager creates and accesses blocks. The concrete types implement specific block storage strategies. +//! BlockManager is an abstract representation to manage blocks. When writing or reading blocks, the +//! BlockManager creates and accesses them. The concrete types implement specific block storage strategies. class BlockManager { public: BlockManager() = delete; @@ -114,14 +114,15 @@ class BlockManager { shared_ptr old_block, ConvertToPersistentMode mode = ConvertToPersistentMode::DESTRUCTIVE); - void UnregisterBlock(BlockHandle &block); + void UnregisterPersistentBlock(BlockHandle &block); //! UnregisterBlock, only accepts non-temporary block ids virtual void UnregisterBlock(block_id_t id); //! Returns a reference to the metadata manager of this block manager. MetadataManager &GetMetadataManager(); + //! Returns the block allocation size of this block manager. - inline idx_t GetBlockAllocSize() const { + idx_t GetBlockAllocSize() const { return block_alloc_size.GetIndex(); } //! Returns the possibly invalid block allocation size of this block manager. @@ -132,15 +133,15 @@ class BlockManager { inline optional_idx GetOptionalBlockHeaderSize() const { return block_header_size; } - //! Block header size including the 8-byte checksum - inline idx_t GetBlockHeaderSize() const { + //! Returns the block header size including the 8-byte checksum of this block manager. + idx_t GetBlockHeaderSize() const { if (!block_header_size.IsValid()) { return Storage::DEFAULT_BLOCK_HEADER_SIZE; } return block_header_size.GetIndex(); } - //! Size of the block available for the user - inline idx_t GetBlockSize() const { + //! Returns the size of the block that is available for usage. + idx_t GetBlockSize() const { return block_alloc_size.GetIndex() - block_header_size.GetIndex(); } //! Sets the block allocation size. This should only happen when initializing an existing database. @@ -167,6 +168,7 @@ class BlockManager { protected: bool BlockIsRegistered(block_id_t block_id); + shared_ptr TryGetBlock(block_id_t block_id); public: template @@ -181,6 +183,8 @@ class BlockManager { } protected: + //! A flag to be flipped in the destructor of the subclass, which is called first. + //! Relevant for some Windows edge cases. bool in_destruction = false; private: @@ -194,9 +198,9 @@ class BlockManager { //! for in-memory block managers. Default to default_block_alloc_size for file-backed block managers. //! This is NOT the actual memory available on a block (block_size). optional_idx block_alloc_size; - //! The size of the block headers (incl. checksum) in this block manager. + //! The size of the block headers (including checksum) in this block manager. //! Defaults to DEFAULT_BLOCK_HEADER_SIZE for in-memory block managers. - //! Default to default_block_header_size for file-backed block managers. + //! Defaults to default_block_header_size for file-backed block managers. optional_idx block_header_size; }; diff --git a/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp b/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp index b4095853b..e6eefe774 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp @@ -13,200 +13,287 @@ #include "duckdb/common/enums/memory_tag.hpp" #include "duckdb/common/file_buffer.hpp" #include "duckdb/common/mutex.hpp" +#include "duckdb/common/numeric_utils.hpp" +#include "duckdb/common/optional_idx.hpp" +#include "duckdb/storage/buffer/buffer_pool_reservation.hpp" #include "duckdb/storage/storage_info.hpp" namespace duckdb { +// Forward declaration. class BlockManager; class BufferHandle; -class BufferPool; +class BufferManager; class DatabaseInstance; - -enum class BlockState : uint8_t { BLOCK_UNLOADED = 0, BLOCK_LOADED = 1 }; - -struct BufferPoolReservation { - MemoryTag tag; - idx_t size {0}; - BufferPool &pool; - - BufferPoolReservation(MemoryTag tag, BufferPool &pool); - BufferPoolReservation(const BufferPoolReservation &) = delete; - BufferPoolReservation &operator=(const BufferPoolReservation &) = delete; - - BufferPoolReservation(BufferPoolReservation &&) noexcept; - BufferPoolReservation &operator=(BufferPoolReservation &&) noexcept; - - ~BufferPoolReservation(); - - void Resize(idx_t new_size); - void Merge(BufferPoolReservation src); -}; - -struct TempBufferPoolReservation : BufferPoolReservation { - TempBufferPoolReservation(MemoryTag tag, BufferPool &pool, idx_t size) : BufferPoolReservation(tag, pool) { - Resize(size); - } - TempBufferPoolReservation(TempBufferPoolReservation &&) = default; - ~TempBufferPoolReservation() { - Resize(0); - } -}; +class BlockHandle; using BlockLock = unique_lock; -class BlockHandle : public enable_shared_from_this { +class BlockMemory : public enable_shared_from_this { public: - BlockHandle(BlockManager &block_manager, block_id_t block_id, MemoryTag tag); - BlockHandle(BlockManager &block_manager, block_id_t block_id, MemoryTag tag, unique_ptr buffer, - DestroyBufferUpon destroy_buffer_upon, idx_t block_size, BufferPoolReservation &&reservation); - ~BlockHandle(); - - BlockManager &block_manager; + BlockMemory(BufferManager &buffer_manager, block_id_t block_id_p, MemoryTag tag_p, idx_t block_alloc_size); + BlockMemory(BufferManager &buffer_manager, block_id_t block_id_p, MemoryTag tag_p, unique_ptr buffer_p, + DestroyBufferUpon destroy_buffer_upon_p, idx_t size_p, BufferPoolReservation &&reservation); + ~BlockMemory(); public: + //! Returns a const reference to the buffer manager. + const BufferManager &GetBufferManager() const { + return buffer_manager; + } + //! Returns a reference to the buffer manager. + BufferManager &GetBufferManager() { + return buffer_manager; + } + //! Returns the block ID. block_id_t BlockId() const { return block_id; } - - idx_t EvictionSequenceNumber() const { - return eviction_seq_num; + //! Locks the memory block. + BlockLock GetLock() { + return BlockLock(lock); } - - idx_t NextEvictionSequenceNumber() { - return ++eviction_seq_num; + //! Verification-only: ensure that the lock matches this memory's lock. + void VerifyMutex(BlockLock &l) const { + D_ASSERT(l.owns_lock()); + D_ASSERT(l.mutex() == &lock); } - - int32_t Readers() const { + //! Returns the block state. + BlockState GetState() const { + return state; + } + //! Sets the block state. + void SetState(BlockState state_p) { + state = state_p; + } + //! Returns true, if the block state is BLOCK_UNLOADED. + bool IsUnloaded() const { + return state == BlockState::BLOCK_UNLOADED; + } + //! Returns the number of readers. + int32_t GetReaders() const { return readers; } + //! Increments the number of readers prior to returning it. + int32_t IncrementReaders() { + return ++readers; + } + //! Decrements the number of readers prior to returning it. int32_t DecrementReaders() { return --readers; } - - inline bool IsSwizzled() const { - return !unswizzled; - } - - inline void SetSwizzling(const char *unswizzler) { - unswizzled = unswizzler; + //! Sets the number of readers. + void SetReaders(int32_t n) { + readers = n; } - + //! Returns the memory tag. MemoryTag GetMemoryTag() const { return tag; } - - inline void SetDestroyBufferUpon(DestroyBufferUpon destroy_buffer_upon_p) { + //! Returns the file buffer type. + FileBufferType GetBufferType() const { + return buffer_type; + } + //! Returns a reference to the unique file buffer pointer while holding the block lock. + unique_ptr &GetBuffer(BlockLock &l) { + VerifyMutex(l); + return GetBuffer(); + } + //! Returns a reference to the unique file buffer pointer. + unique_ptr &GetBuffer() { + return buffer; + } + //! Sets the file buffer. + void SetBuffer(unique_ptr buffer_p) { + buffer = std::move(buffer_p); + } + //! Returns the eviction sequence number. + idx_t GetEvictionSequenceNumber() const { + return eviction_seq_num; + } + //! Increments the eviction sequence number prior to returning it. + idx_t NextEvictionSequenceNumber() { + return ++eviction_seq_num; + } + //! Get the LRU timestamp. + int64_t GetLRUTimestamp() const { + return lru_timestamp_msec; + } + //! Set the LRU timestamp. + void SetLRUTimestamp(int64_t timestamp_msec) { + lru_timestamp_msec = timestamp_msec; + } + //! Set the buffer destruction policy. + void SetDestroyBufferUpon(DestroyBufferUpon destroy_buffer_upon_p) { destroy_buffer_upon = destroy_buffer_upon_p; } - - inline bool MustAddToEvictionQueue() const { + //! Returns true, if the buffer must be added to the eviction queue. + bool MustAddToEvictionQueue() const { return destroy_buffer_upon != DestroyBufferUpon::UNPIN; } - - inline bool MustWriteToTemporaryFile() const { + //! Returns true, if the buffer cannot be destroyed, but must be kept alive in a temporary file. + bool MustWriteToTemporaryFile() const { return destroy_buffer_upon == DestroyBufferUpon::BLOCK; } - - inline idx_t GetMemoryUsage() const { + //! Returns the memory usage. + idx_t GetMemoryUsage() const { return memory_usage; } - - bool IsUnloaded() const { - return state == BlockState::BLOCK_UNLOADED; + //! Sets the memory usage. + void SetMemoryUsage(idx_t usage) { + memory_usage = usage; } - + //! Get the memory charge while holding the block lock. + BufferPoolReservation &GetMemoryCharge(BlockLock &l) { + VerifyMutex(l); + return GetMemoryCharge(); + } + //! Get the memory charge. + BufferPoolReservation &GetMemoryCharge() { + return memory_charge; + } + //! Resize the memory charge. + void ResizeMemory(BlockLock &l, idx_t alloc_size) { + VerifyMutex(l); + memory_charge.Resize(alloc_size); + } + //! Merge two memory charges. + void MergeMemoryReservation(BlockLock &l, BufferPoolReservation reservation) { + VerifyMutex(l); + memory_charge.Merge(std::move(reservation)); + } + //! Returns true, if there is a swizzled memory pointer, else false. + bool IsSwizzled() const { + return !unswizzled; + } + //! Sets the swizzled memory pointer. + void SetSwizzling(const char *unswizzler) { + unswizzled = unswizzler; + } + //! Sets the eviction queue index. void SetEvictionQueueIndex(const idx_t index) { - // can only be set once + // The index can only be set once. D_ASSERT(eviction_queue_idx == DConstants::INVALID_INDEX); - // MANAGED_BUFFER only (at least, for now) + // It can only be set for managed buffers (for now). D_ASSERT(GetBufferType() == FileBufferType::MANAGED_BUFFER); eviction_queue_idx = index; } - + //! Returns the eviction queue index. idx_t GetEvictionQueueIndex() const { return eviction_queue_idx; } - FileBufferType GetBufferType() const { - return buffer_type; - } - - BlockState GetState() const { - return state; - } - - int64_t GetLRUTimestamp() const { - return lru_timestamp_msec; - } - - void SetLRUTimestamp(int64_t timestamp_msec) { - lru_timestamp_msec = timestamp_msec; - } - - BlockLock GetLock() { - return BlockLock(lock); - } - - //! Gets a reference to the buffer - the lock must be held - unique_ptr &GetBuffer(BlockLock &l); - +public: void ChangeMemoryUsage(BlockLock &l, int64_t delta); - BufferPoolReservation &GetMemoryCharge(BlockLock &l); - //! Merge a new memory reservation - void MergeMemoryReservation(BlockLock &, BufferPoolReservation reservation); - //! Resize the memory allocation - void ResizeMemory(BlockLock &, idx_t alloc_size); - - //! Resize the actual buffer - void ResizeBuffer(BlockLock &, idx_t block_size, int64_t memory_delta); - - BufferHandle Load(QueryContext context, unique_ptr buffer = nullptr); - - BufferHandle LoadFromBuffer(BlockLock &l, data_ptr_t data, unique_ptr reusable_buffer, - BufferPoolReservation reservation); - unique_ptr UnloadAndTakeBlock(BlockLock &); - void Unload(BlockLock &); - - //! Returns whether or not the block can be unloaded - //! Note that while this method does not require a lock, whether or not a block can be unloaded can change if the - //! lock is not held + void ConvertToPersistent(BlockLock &l, BlockHandle &new_block, unique_ptr new_buffer); + void ResizeBuffer(BlockLock &l, idx_t block_size, idx_t block_header_size, int64_t memory_delta); + //! Returns whether the block can be unloaded or not. + //! The state here can change if the block lock is held. + //! However, this method does not hold the block lock. bool CanUnload() const; - - void ConvertToPersistent(BlockLock &, BlockHandle &new_block, unique_ptr new_buffer); + unique_ptr UnloadAndTakeBlock(BlockLock &l); + void Unload(BlockLock &l); private: - void VerifyMutex(unique_lock &l) const; - -private: - //! The block-level lock + //! A reference to the buffer manager. + BufferManager &buffer_manager; + //! The block id of the block. + const block_id_t block_id; + //! The block-level lock. mutex lock; - //! Whether or not the block is loaded/unloaded + //! Whether the block is loaded or unloaded. atomic state; - //! Amount of concurrent readers + //! The number of concurrent readers. atomic readers; - //! The block id of the block - const block_id_t block_id; - //! Memory tag + //! The memory tag. const MemoryTag tag; - //! File buffer type + //! The file buffer type. const FileBufferType buffer_type; - //! Pointer to loaded data (if any) + //! A pointer to the loaded data, if any. unique_ptr buffer; - //! Internal eviction sequence number + //! The internal eviction sequence number. atomic eviction_seq_num; - //! LRU timestamp (for age-based eviction) + //! The LRU timestamp for age-based eviction. atomic lru_timestamp_msec; - //! When to destroy the data buffer + //! When to destroy the data buffer. atomic destroy_buffer_upon; - //! The memory usage of the block (when loaded). If we are pinning/loading - //! an unloaded block, this tells us how much memory to reserve. + //! The memory usage of the block when loaded. + //! Determines the memory to reserve when pinning/loading an unloaded block. atomic memory_usage; - //! Current memory reservation / usage + //! The current memory reservation/usage. BufferPoolReservation memory_charge; - //! Does the block contain any memory pointers? + //! Swizzled memory pointers. const char *unswizzled; - //! Index for eviction queue (FileBufferType::MANAGED_BUFFER only, for now) + //! The eviction queue index, currently only FileBufferType::MANAGED_BUFFER. atomic eviction_queue_idx; }; +class BlockHandle : public enable_shared_from_this { +public: + BlockHandle(BlockManager &block_manager, block_id_t block_id, MemoryTag tag); + BlockHandle(BlockManager &block_manager, block_id_t block_id, MemoryTag tag, unique_ptr buffer, + DestroyBufferUpon destroy_buffer_upon, idx_t size, BufferPoolReservation &&reservation); + ~BlockHandle(); + +public: + //! Returns a reference to the block manager. + BlockManager &GetBlockManager() const { + return block_manager; + } + //! Returns the block id. + block_id_t BlockId() const { + return block_id; + } + //! Returns the block allocation size of this block. + idx_t GetBlockAllocSize() const { + return block_alloc_size; + } + //! Returns the block header size including the 8-byte checksum. + idx_t GetBlockHeaderSize() const { + return block_header_size; + } + //! Returns the size of the block that is available for usage, as determined by the block manager that created the + //! block. The block_alloc_size can differ from the memory_usage for blocks managed by the temporary block manager, + //! thus, this should only be called for persistent blocks. + idx_t GetBlockSize() const { + return block_alloc_size - block_header_size; + } + //! Returns a const reference to the memory of a block. + const BlockMemory &GetMemory() const { + return memory; + } + //! Returns a reference to the memory of a block. + BlockMemory &GetMemory() { + return memory; + } + //! Returns a weak pointer to the memory of a block. + weak_ptr GetMemoryWeak() const { + return weak_ptr(memory_p); + } + +public: + BufferHandle LoadFromBuffer(BlockLock &l, data_ptr_t data, unique_ptr reusable_buffer, + BufferPoolReservation reservation); + BufferHandle Load(QueryContext context, unique_ptr buffer = nullptr); + +private: + //! The block manager, which loads the block. + BlockManager &block_manager; + + //! The block allocation size, which is determined by the block manager creating the block. + //! For non-temporary block managers the block_alloc_size corresponds to the memory_usage. + //! If we are pinning/loading an unloaded block, then we know how much memory to reserve. + //! This is NOT the actual memory available on a block. + idx_t block_alloc_size; + //! The size of the block header, including the checksum. + idx_t block_header_size; + //! The block id of the block. + const block_id_t block_id; + + //! Pointer to the underlying memory of the block. + const shared_ptr memory_p; + //! Memory for fast access to the block memory. + BlockMemory &memory; +}; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp b/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp index a77b34ef7..a591da592 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp @@ -10,31 +10,35 @@ #include "duckdb/common/array.hpp" #include "duckdb/common/enums/memory_tag.hpp" +#include "duckdb/common/exception.hpp" #include "duckdb/common/file_buffer.hpp" #include "duckdb/common/mutex.hpp" +#include "duckdb/common/optional_ptr.hpp" #include "duckdb/common/typedefs.hpp" #include "duckdb/storage/buffer/block_handle.hpp" namespace duckdb { class TemporaryMemoryManager; +class ObjectCache; struct EvictionQueue; struct BufferEvictionNode { BufferEvictionNode() { } - BufferEvictionNode(weak_ptr handle_p, idx_t eviction_seq_num); + BufferEvictionNode(weak_ptr block_memory_p, idx_t eviction_seq_num); - weak_ptr handle; + weak_ptr memory_p; idx_t handle_sequence_number; - bool CanUnload(BlockHandle &handle_p); - shared_ptr TryGetBlockHandle(); + bool CanUnload(BlockMemory &memory); + shared_ptr TryGetBlockMemory(); }; //! The BufferPool is in charge of handling memory management for one or more databases. It defines memory limits //! and implements priority eviction among all users of the pool. class BufferPool { + friend class BlockMemory; friend class BlockHandle; friend class BlockManager; friend class BufferManager; @@ -63,6 +67,15 @@ class BufferPool { TemporaryMemoryManager &GetTemporaryMemoryManager(); + //! Take per-database ObjectCache under buffer pool's memory management. + //! Notice, object cache should be registered for at most once, otherwise InvalidInput exception is thrown. + void SetObjectCache(ObjectCache *object_cache_p) { + if (object_cache != nullptr) { + throw InvalidInputException("Object cache has already been registered in buffer pool, cannot re-register!"); + } + object_cache = object_cache_p; + } + protected: //! Evict blocks until the currently used memory + extra_memory fit, returns false if this was not possible //! (i.e. not enough blocks could be evicted) @@ -79,18 +92,22 @@ class BufferPool { virtual EvictionResult EvictBlocksInternal(EvictionQueue &queue, MemoryTag tag, idx_t extra_memory, idx_t memory_limit, unique_ptr *buffer = nullptr); + //! Evict object cache entries if needed. + EvictionResult EvictObjectCacheEntries(MemoryTag tag, idx_t extra_memory, idx_t memory_limit); + //! Purge all blocks that haven't been pinned within the last N seconds idx_t PurgeAgedBlocks(uint32_t max_age_sec); idx_t PurgeAgedBlocksInternal(EvictionQueue &queue, uint32_t max_age_sec, int64_t now, int64_t limit); + //! Garbage collect dead nodes in the eviction queue. void PurgeQueue(const BlockHandle &handle); //! Add a buffer handle to the eviction queue. Returns true, if the queue is //! ready to be purged, and false otherwise. bool AddToEvictionQueue(shared_ptr &handle); //! Gets the eviction queue for the specified type - EvictionQueue &GetEvictionQueueForBlockHandle(const BlockHandle &handle); + EvictionQueue &GetEvictionQueueForBlockMemory(const BlockMemory &memory); //! Increments the dead nodes for the queue with specified type - void IncrementDeadNodes(const BlockHandle &handle); + void IncrementDeadNodes(const BlockMemory &memory); //! How many eviction queue types we have (BLOCK and EXTERNAL_FILE go into same queue) static constexpr idx_t EVICTION_QUEUE_TYPES = FILE_BUFFER_TYPE_COUNT - 1; @@ -163,6 +180,8 @@ class BufferPool { mutable MemoryUsage memory_usage; //! The block allocator BlockAllocator &block_allocator; + //! Per-database singleton object cache managed by buffer pool. + optional_ptr object_cache = nullptr; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool_reservation.hpp b/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool_reservation.hpp new file mode 100644 index 000000000..4140c9f00 --- /dev/null +++ b/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool_reservation.hpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/storage/buffer/buffer_pool_reservation.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/enums/memory_tag.hpp" + +namespace duckdb { + +enum class BlockState : uint8_t { BLOCK_UNLOADED = 0, BLOCK_LOADED = 1 }; + +// Forward declaration. +class BufferPool; + +struct BufferPoolReservation { + MemoryTag tag; + idx_t size {0}; + BufferPool &pool; + + BufferPoolReservation(MemoryTag tag, BufferPool &pool); + BufferPoolReservation(const BufferPoolReservation &) = delete; + BufferPoolReservation &operator=(const BufferPoolReservation &) = delete; + + BufferPoolReservation(BufferPoolReservation &&) noexcept; + BufferPoolReservation &operator=(BufferPoolReservation &&) noexcept; + + virtual ~BufferPoolReservation(); + + void Resize(idx_t new_size); + void Merge(BufferPoolReservation src); +}; + +struct TempBufferPoolReservation : BufferPoolReservation { + TempBufferPoolReservation(MemoryTag tag, BufferPool &pool, idx_t size) : BufferPoolReservation(tag, pool) { + Resize(size); + } + TempBufferPoolReservation(TempBufferPoolReservation &&) = default; + ~TempBufferPoolReservation() override { + Resize(0); + } +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp b/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp index 3d4f5e595..92b27cd88 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp @@ -17,7 +17,7 @@ #include "duckdb/storage/buffer_manager.hpp" namespace duckdb { - +class BlockMemory; class Allocator; class BufferPool; class TemporaryMemoryManager; @@ -54,8 +54,6 @@ class BufferManager { virtual BufferHandle Allocate(MemoryTag tag, idx_t block_size, bool can_destroy = true) = 0; //! Allocate block-based memory and pin it. virtual BufferHandle Allocate(MemoryTag tag, BlockManager *block_manager, bool can_destroy = true) = 0; - //! Reallocate a pinned in-memory buffer. - virtual void ReAllocate(shared_ptr &handle, idx_t block_size) = 0; //! Pin a block handle. virtual BufferHandle Pin(shared_ptr &handle) = 0; virtual BufferHandle Pin(const QueryContext &context, shared_ptr &handle) = 0; @@ -120,6 +118,8 @@ class BufferManager { FileBufferType type = FileBufferType::MANAGED_BUFFER); //! Get the buffer pool. virtual BufferPool &GetBufferPool() const; + //! Get the const database. + virtual const DatabaseInstance &GetDatabase() const = 0; //! Get the database. virtual DatabaseInstance &GetDatabase() = 0; //! Get the manager assigning reservations for temporary memory, e.g., for query intermediates. @@ -134,8 +134,8 @@ class BufferManager { //! Read a temporary buffer. virtual unique_ptr ReadTemporaryBuffer(QueryContext context, MemoryTag tag, BlockHandle &block, unique_ptr buffer); - //! Delete the temporary file containing the block. - virtual void DeleteTemporaryFile(BlockHandle &block); + //! Delete the temporary file containing the block memory. + virtual void DeleteTemporaryFile(BlockMemory &memory); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/checkpoint/checkpoint_options.hpp b/src/duckdb/src/include/duckdb/storage/checkpoint/checkpoint_options.hpp index 2ccc15c70..dd6a7faf0 100644 --- a/src/duckdb/src/include/duckdb/storage/checkpoint/checkpoint_options.hpp +++ b/src/duckdb/src/include/duckdb/storage/checkpoint/checkpoint_options.hpp @@ -9,6 +9,8 @@ #pragma once #include "duckdb/common/enums/checkpoint_type.hpp" +#include "duckdb/common/mutex.hpp" +#include "duckdb/common/optional_ptr.hpp" namespace duckdb { @@ -22,6 +24,9 @@ struct CheckpointOptions { CheckpointAction action; CheckpointType type; transaction_t transaction_id; + //! The WAL lock - in case we are holding it during the entire checkpoint. + //! This is only required if we are doing a checkpoint instead of writing to the WAL + optional_ptr> wal_lock; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/checkpoint/string_checkpoint_state.hpp b/src/duckdb/src/include/duckdb/storage/checkpoint/string_checkpoint_state.hpp index a13c72943..a598e74a9 100644 --- a/src/duckdb/src/include/duckdb/storage/checkpoint/string_checkpoint_state.hpp +++ b/src/duckdb/src/include/duckdb/storage/checkpoint/string_checkpoint_state.hpp @@ -55,9 +55,14 @@ struct UncompressedStringSegmentState : public CompressedSegmentState { string GetSegmentInfo() const override; + void InsertOverflowBlock(block_id_t block_id, reference block); + reference FindOverflowBlock(block_id_t block_id); + private: mutex block_lock; unordered_map> handles; + + StorageLock overflow_blocks_lock; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/compression/alp/alp_scan.hpp b/src/duckdb/src/include/duckdb/storage/compression/alp/alp_scan.hpp index 0aa9f00c8..188b5f1bb 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/alp/alp_scan.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/alp/alp_scan.hpp @@ -124,7 +124,7 @@ struct AlpScanState : public SegmentScanState { // Load the offset (metadata) indicating where the vector data starts metadata_ptr -= AlpConstants::METADATA_POINTER_SIZE; auto data_byte_offset = Load(metadata_ptr); - D_ASSERT(data_byte_offset < segment.GetBlockManager().GetBlockSize()); + D_ASSERT(data_byte_offset < segment.GetBlockSize()); idx_t vector_size = MinValue((idx_t)AlpConstants::ALP_VECTOR_SIZE, (count - total_value_count)); diff --git a/src/duckdb/src/include/duckdb/storage/compression/alprd/alprd_scan.hpp b/src/duckdb/src/include/duckdb/storage/compression/alprd/alprd_scan.hpp index a05b2026c..47e29434d 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/alprd/alprd_scan.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/alprd/alprd_scan.hpp @@ -143,7 +143,7 @@ struct AlpRDScanState : public SegmentScanState { // Load the offset (metadata) indicating where the vector data starts metadata_ptr -= AlpRDConstants::METADATA_POINTER_SIZE; auto data_byte_offset = Load(metadata_ptr); - D_ASSERT(data_byte_offset < segment.GetBlockManager().GetBlockSize()); + D_ASSERT(data_byte_offset < segment.GetBlockSize()); idx_t vector_size = MinValue((idx_t)AlpRDConstants::ALP_VECTOR_SIZE, (count - total_value_count)); diff --git a/src/duckdb/src/include/duckdb/storage/compression/bitpacking.hpp b/src/duckdb/src/include/duckdb/storage/compression/bitpacking.hpp index 6b87e5bb1..0e1131f8f 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/bitpacking.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/bitpacking.hpp @@ -14,7 +14,4 @@ namespace duckdb { enum class BitpackingMode : uint8_t { INVALID, AUTO, CONSTANT, CONSTANT_DELTA, DELTA_FOR, FOR }; -BitpackingMode BitpackingModeFromString(const string &str); -string BitpackingModeToString(const BitpackingMode &mode); - } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_scan.hpp b/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_scan.hpp index b29ecc8d1..6cd49a1e6 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_scan.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_scan.hpp @@ -187,7 +187,7 @@ struct ChimpScanState : public SegmentScanState { // Load the offset indicating where a groups data starts metadata_ptr -= sizeof(uint32_t); auto data_byte_offset = Load(metadata_ptr); - D_ASSERT(data_byte_offset < segment.GetBlockManager().GetBlockSize()); + D_ASSERT(data_byte_offset < segment.GetBlockSize()); // Only used for point queries (void)data_byte_offset; diff --git a/src/duckdb/src/include/duckdb/storage/compression/patas/patas_scan.hpp b/src/duckdb/src/include/duckdb/storage/compression/patas/patas_scan.hpp index 74a0cf9a9..ea1f95fb0 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/patas/patas_scan.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/patas/patas_scan.hpp @@ -154,7 +154,7 @@ struct PatasScanState : public SegmentScanState { // Load the offset indicating where a groups data starts metadata_ptr -= sizeof(uint32_t); auto data_byte_offset = Load(metadata_ptr); - D_ASSERT(data_byte_offset < segment.GetBlockManager().GetBlockSize()); + D_ASSERT(data_byte_offset < segment.GetBlockSize()); // Initialize the byte_reader with the data values for the group group_state.Init(segment_data + data_byte_offset); diff --git a/src/duckdb/src/include/duckdb/storage/compression/zstd/zstd.hpp b/src/duckdb/src/include/duckdb/storage/compression/zstd/zstd.hpp new file mode 100644 index 000000000..30f000bef --- /dev/null +++ b/src/duckdb/src/include/duckdb/storage/compression/zstd/zstd.hpp @@ -0,0 +1,356 @@ +#pragma once + +#include "duckdb/common/constants.hpp" +#include "duckdb/common/numeric_utils.hpp" +#include "duckdb/function/compression_function.hpp" +#include "duckdb/common/types/string_type.hpp" +#include "duckdb/common/helper.hpp" +#include "duckdb/storage/storage_info.hpp" +#include "duckdb/common/optional_idx.hpp" +#include "duckdb/storage/buffer/buffer_handle.hpp" +#include "duckdb/storage/table/column_segment.hpp" + +namespace duckdb { + +using page_id_t = int64_t; +using page_offset_t = uint32_t; +using uncompressed_size_t = uint64_t; +using compressed_size_t = uint64_t; +using string_length_t = uint32_t; + +struct ZSTDCompressionBufferFlags { +public: + ZSTDCompressionBufferFlags() : value(0) { + } + ZSTDCompressionBufferFlags(const ZSTDCompressionBufferFlags &other) : value(other.value) { + } + ~ZSTDCompressionBufferFlags() = default; + + ZSTDCompressionBufferFlags &operator=(const ZSTDCompressionBufferFlags &other) { + value = other.value; + return *this; + } + + bool operator==(const ZSTDCompressionBufferFlags &other) const { + return other.value == value; + } + bool operator!=(const ZSTDCompressionBufferFlags &other) const { + return !(*this == other); + } + +public: + // Bit layout + static constexpr uint8_t VECTOR_METADATA_BIT = 0; + static constexpr uint8_t STRING_METADATA_BIT = 1; + static constexpr uint8_t DATA_BIT = 2; + + // Getters + bool HasVectorMetadata() const { + return IsSet(); + } + bool HasStringMetadata() const { + return IsSet(); + } + bool HasData() const { + return IsSet(); + } + + // Setters + void SetVectorMetadata() { + Set(); + } + void SetStringMetadata() { + Set(); + } + void SetData() { + Set(); + } + + // Unsetters + void UnsetVectorMetadata() { + Unset(); + } + void UnsetStringMetadata() { + Unset(); + } + void UnsetData() { + Unset(); + } + + // Clear all flags + void Clear() { + value = 0; + } + +protected: + template + bool IsSet() const { + static const uint8_t FLAG = (1 << BIT); + return (value & FLAG) == FLAG; + } + + template + void Set() { + static const uint8_t FLAG = (1 << BIT); + value |= FLAG; + } + + template + void Unset() { + static const uint8_t FLAG = (1 << BIT); + value &= ~FLAG; + } + +private: + uint8_t value; +}; + +struct ZSTDCompressionBufferState { + //! Flags indicating use of this buffer + ZSTDCompressionBufferFlags flags; + page_offset_t offset = 0; + bool full = false; +}; + +struct ZSTDCompressionBufferCollection { +public: + enum class Slot : uint8_t { SEGMENT, OVERFLOW_0, OVERFLOW_1 }; + +public: + struct BufferData { + public: + BufferData(BufferHandle &handle, ZSTDCompressionBufferState &state, Slot slot) + : handle(handle), state(state), slot(slot) { + } + + public: + BufferHandle &handle; + ZSTDCompressionBufferState &state; + Slot slot; + }; + +public: + page_id_t GetCurrentId() const { +#ifdef DEBUG + if (!buffer_index.IsValid() || buffer_index == 0) { + D_ASSERT(block_id == INVALID_BLOCK); + } else { + D_ASSERT(block_id != INVALID_BLOCK); + } +#endif + return block_id; + } + +public: + void SetCurrentBuffer(Slot slot, page_offset_t offset = 0) { + idx_t index; + switch (slot) { + case Slot::SEGMENT: + index = 0; + break; + case Slot::OVERFLOW_0: + index = 1; + break; + case Slot::OVERFLOW_1: + index = 2; + break; + default: + throw InternalException("ZSTDCompressionBufferCollection::Slot value not handled"); + }; + buffer_index = index; + buffer_states[index].offset = offset; + } + page_offset_t &GetCurrentOffset() { + if (!buffer_index.IsValid()) { + throw InternalException( + "(ZSTDCompressionBufferCollection::GetCurrentOffset) Can't get BufferHandle, no buffer set yet!"); + } + auto index = buffer_index.GetIndex(); + auto &offset = buffer_states[index].offset; + return offset; + } + void AlignCurrentOffset() { + auto &offset = GetCurrentOffset(); + offset = UnsafeNumericCast( + AlignValue(UnsafeNumericCast(offset))); + } + BufferHandle &BufferHandleMutable() { + if (!buffer_index.IsValid()) { + throw InternalException( + "(ZSTDCompressionBufferCollection::BufferHandleMutable) Can't get BufferHandle, no buffer set yet!"); + } + auto index = buffer_index.GetIndex(); + if (index == 0) { + return segment_handle; + } + D_ASSERT(index < 3); + return extra_pages[index - 1]; + } + vector GetBufferData(bool include_segment) { + vector res; + for (idx_t i = 0; i < 3; i++) { + if (!i) { + if (include_segment) { + res.emplace_back(segment_handle, buffer_states[i], Slot::SEGMENT); + } + continue; + } + res.emplace_back(extra_pages[i - 1], buffer_states[i], i == 1 ? Slot::OVERFLOW_0 : Slot::OVERFLOW_1); + } + return res; + } + data_ptr_t GetCurrentBufferPtr() { + if (!buffer_index.IsValid()) { + throw InternalException( + "(ZSTDCompressionBufferCollection::GetCurrentBufferPtr) Can't get BufferHandle, no buffer set yet!"); + } + auto index = buffer_index.GetIndex(); + auto &state = buffer_states[index]; + return BufferHandleMutable().Ptr() + state.offset; + } + bool CanFlush() const { + if (!buffer_index.IsValid()) { + throw InternalException( + "(ZSTDCompressionBufferCollection::CanFlush) Can't determine CanFlush, no buffer set yet!"); + } + auto index = buffer_index.GetIndex(); + if (index == 0) { + //! Can't flush the segment buffer + return false; + } + auto &flags = buffer_states[index].flags; + return !flags.HasVectorMetadata() && !flags.HasStringMetadata(); + } + ZSTDCompressionBufferFlags &GetCurrentFlags() { + return GetCurrentBufferState().flags; + } + ZSTDCompressionBufferState &GetCurrentBufferState() { + if (!buffer_index.IsValid()) { + throw InternalException( + "(ZSTDCompressionBufferCollection::GetCurrentBufferState) Can't get BufferState, no buffer set yet!"); + } + return buffer_states[buffer_index.GetIndex()]; + } + bool IsOnSegmentBuffer() const { + if (!buffer_index.IsValid()) { + return false; + } + return buffer_index.GetIndex() == 0; + } + +public: + //! Current block-id of the overflow page we're writing + //! NOTE: INVALID_BLOCK means we haven't spilled to an overflow page yet + block_id_t block_id = INVALID_BLOCK; + + //! The current segment + buffer of the segment + unique_ptr segment; + BufferHandle segment_handle; + // Non-segment buffers + BufferHandle extra_pages[2]; + + //! 0: segment_handle + //! 1: extra_pages[0]; + //! 2: extra_pages[1]; + ZSTDCompressionBufferState buffer_states[3]; + +private: + optional_idx buffer_index; +}; + +//! State for the current segment (a collection of vectors) +struct ZSTDCompressionSegmentState { +public: + ZSTDCompressionSegmentState() { + } + +public: + void InitializeSegment(ZSTDCompressionBufferCollection &buffer_collection, idx_t vectors_in_segment) { + total_vectors_in_segment = vectors_in_segment; + vector_in_segment_count = 0; + buffer_collection.block_id = INVALID_BLOCK; + + //! Have to be on the segment handle + if (!buffer_collection.IsOnSegmentBuffer()) { + throw InternalException("(ZSTDCompressionSegmentState::InitializeSegment) Can't InitializeSegment on a " + "non-segment buffer!"); + } + auto base = buffer_collection.segment_handle.Ptr(); + page_offset_t offset = 0; + page_ids = reinterpret_cast(base + offset); + offset += (sizeof(page_id_t) * vectors_in_segment); + + offset = AlignValue(offset); + page_offsets = reinterpret_cast(base + offset); + offset += (sizeof(page_offset_t) * vectors_in_segment); + + offset = AlignValue(offset); + uncompressed_sizes = reinterpret_cast(base + offset); + offset += (sizeof(uncompressed_size_t) * vectors_in_segment); + + offset = AlignValue(offset); + compressed_sizes = reinterpret_cast(base + offset); + offset += (sizeof(compressed_size_t) * vectors_in_segment); + + buffer_collection.buffer_states[0].offset = offset; + } + +public: + //! Amount of vectors in this segment, determined during analyze + idx_t total_vectors_in_segment = 0xDEADBEEF; + //! The amount of vectors we've seen in the current segment + idx_t vector_in_segment_count = 0; + + page_id_t *page_ids = nullptr; + page_offset_t *page_offsets = nullptr; + uncompressed_size_t *uncompressed_sizes = nullptr; + compressed_size_t *compressed_sizes = nullptr; +}; + +//===--------------------------------------------------------------------===// +// Vector metadata +//===--------------------------------------------------------------------===// +struct ZSTDCompressionVectorState { +public: + ZSTDCompressionVectorState() { + } + +public: + bool AddStringLength(const string_t &str) { + string_lengths[tuple_count++] = UnsafeNumericCast(str.GetSize()); + return tuple_count >= vector_size; + } + + void Initialize(idx_t expected_tuple_count, ZSTDCompressionBufferCollection &buffer_collection, + const CompressionInfo &info) { + vector_size = expected_tuple_count; + + auto current_offset = buffer_collection.GetCurrentOffset(); + //! Mark where the vector begins (page_id + page_offset) + starting_offset = current_offset; + starting_page = buffer_collection.GetCurrentId(); + + //! Set the string_lengths destination and save in what buffer its stored + buffer_collection.GetCurrentFlags().SetStringMetadata(); + string_lengths = reinterpret_cast(buffer_collection.GetCurrentBufferPtr()); + + //! Finally forward the current_buffer_ptr to point *after* all string lengths we'll write + buffer_collection.GetCurrentOffset() += expected_tuple_count * sizeof(string_length_t); + } + +public: + page_id_t starting_page; + page_offset_t starting_offset; + + idx_t uncompressed_size = 0; + idx_t compressed_size = 0; + string_length_t *string_lengths = nullptr; + + bool in_vector = false; + //! Amount of tuples we have seen for the current vector + idx_t tuple_count = 0; + //! The expected size of this vector (ZSTD_VECTOR_SIZE except for the last one) + idx_t vector_size; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/data_table.hpp b/src/duckdb/src/include/duckdb/storage/data_table.hpp index b52e9a011..11902c01a 100644 --- a/src/duckdb/src/include/duckdb/storage/data_table.hpp +++ b/src/duckdb/src/include/duckdb/storage/data_table.hpp @@ -183,7 +183,7 @@ class DataTable : public enable_shared_from_this { const std::function &function); //! Merge a row group collection directly into this table - appending it to the end of the table without copying - void MergeStorage(RowGroupCollection &data, TableIndexList &indexes, optional_ptr commit_state); + void MergeStorage(RowGroupCollection &data, optional_ptr commit_state); //! Appends a chunk with the row ids [row_start, ..., row_start + chunk.size()] to all indexes of the table. //! If an index is bound, it appends table_chunk. Else, it buffers index_chunk. @@ -276,7 +276,7 @@ class DataTable : public enable_shared_from_this { //! AddIndex initializes an index and adds it to the table's index list. //! It is either empty, or initialized via its index storage information. void AddIndex(const ColumnList &columns, const vector &column_indexes, const IndexConstraintType type, - const IndexStorageInfo &info); + IndexStorageInfo index_info); //! AddIndex moves an index to this table's index list. void AddIndex(unique_ptr index); diff --git a/src/duckdb/src/include/duckdb/storage/index_storage_info.hpp b/src/duckdb/src/include/duckdb/storage/index_storage_info.hpp index c60d7e599..838662787 100644 --- a/src/duckdb/src/include/duckdb/storage/index_storage_info.hpp +++ b/src/duckdb/src/include/duckdb/storage/index_storage_info.hpp @@ -43,6 +43,13 @@ struct IndexStorageInfo { IndexStorageInfo() {}; explicit IndexStorageInfo(const string &name) : name(name) {}; + //! Disable copy constructor and copy assignment, this type's lifetime is explicitly managed. + IndexStorageInfo(const IndexStorageInfo &) = delete; + IndexStorageInfo &operator=(const IndexStorageInfo &) = delete; + + IndexStorageInfo(IndexStorageInfo &&) = default; + IndexStorageInfo &operator=(IndexStorageInfo &&) = default; + //! The name. string name; //! The storage root. diff --git a/src/duckdb/src/include/duckdb/storage/object_cache.hpp b/src/duckdb/src/include/duckdb/storage/object_cache.hpp index e2a0de155..5d4cb6ef9 100644 --- a/src/duckdb/src/include/duckdb/storage/object_cache.hpp +++ b/src/duckdb/src/include/duckdb/storage/object_cache.hpp @@ -9,14 +9,31 @@ #pragma once #include "duckdb/common/common.hpp" +#include "duckdb/common/enums/memory_tag.hpp" #include "duckdb/common/lru_cache.hpp" #include "duckdb/common/mutex.hpp" #include "duckdb/common/string.hpp" #include "duckdb/common/unordered_map.hpp" #include "duckdb/main/database.hpp" +#include "duckdb/storage/buffer/buffer_pool_reservation.hpp" namespace duckdb { +struct BufferPoolPayload { + explicit BufferPoolPayload(unique_ptr &&res) : reservation(std::move(res)) { + } + ~BufferPoolPayload() { + reservation->Resize(0); + } + idx_t GetWeight() const { + return reservation->size; + } + unique_ptr reservation; +}; + +// Forward declaration. +class BufferPool; + //! ObjectCache is the base class for objects caches in DuckDB class ObjectCacheEntry { public: @@ -30,20 +47,22 @@ class ObjectCacheEntry { virtual optional_idx GetEstimatedCacheMemory() const = 0; }; +struct CleanupBufferPool { + void operator()(unique_ptr &buffer) { + D_ASSERT(buffer); + buffer->Resize(0); + } +}; + class ObjectCache { public: //! Default max memory 8GiB for non-evictable cache entries. - // - // TODO(hjiang): Hard-code a large enough memory consumption upper bound, which is likely a non-regression change. - // I will followup with another PR before v1.5.0 release to provide a user option to tune. - // - // A few consideration here: should we cap object cache memory consumption with duckdb max memory or separate. static constexpr idx_t DEFAULT_MAX_MEMORY = 8ULL * 1024 * 1024 * 1024; - ObjectCache() : ObjectCache(DEFAULT_MAX_MEMORY) { + explicit ObjectCache(BufferPool &buffer_pool_p) : ObjectCache(DEFAULT_MAX_MEMORY, buffer_pool_p) { } - explicit ObjectCache(idx_t max_memory) : lru_cache(max_memory) { + ObjectCache(idx_t max_memory, BufferPool &buffer_pool_p) : lru_cache(max_memory), buffer_pool(buffer_pool_p) { } shared_ptr GetObject(const string &key) { @@ -93,10 +112,12 @@ class ObjectCache { const bool is_evictable = estimated_memory.IsValid(); if (!is_evictable) { non_evictable_entries[key] = value; - } else { - lru_cache.Put(key, value, estimated_memory.GetIndex()); + return value; } + auto reservation = + make_uniq(MemoryTag::OBJECT_CACHE, buffer_pool, estimated_memory.GetIndex()); + lru_cache.Put(key, value, std::move(reservation)); return value; } @@ -112,7 +133,10 @@ class ObjectCache { non_evictable_entries[std::move(key)] = std::move(value); return; } - lru_cache.Put(std::move(key), std::move(value), estimated_memory.GetIndex()); + + auto reservation = + make_uniq(MemoryTag::OBJECT_CACHE, buffer_pool, estimated_memory.GetIndex()); + lru_cache.Put(std::move(key), std::move(value), std::move(reservation)); } void Delete(const string &key) { @@ -129,23 +153,35 @@ class ObjectCache { idx_t GetMaxMemory() const { const lock_guard lock(lock_mutex); - return lru_cache.MaxMemory(); + return lru_cache.Capacity(); } idx_t GetCurrentMemory() const { const lock_guard lock(lock_mutex); - return lru_cache.CurrentMemory(); + return lru_cache.CurrentTotalWeight(); } size_t GetEntryCount() const { const lock_guard lock(lock_mutex); return lru_cache.Size() + non_evictable_entries.size(); } + bool IsEmpty() const { + const lock_guard lock(lock_mutex); + return lru_cache.IsEmpty() && non_evictable_entries.empty(); + } + + idx_t EvictToReduceMemory(idx_t target_bytes) { + const lock_guard lock(lock_mutex); + return lru_cache.EvictToReduceAtLeast(target_bytes); + } private: mutable mutex lock_mutex; //! LRU cache for evictable entries - SharedLruCache lru_cache; + + SharedLruCache lru_cache; //! Separate storage for non-evictable entries (i.e., encryption keys) unordered_map> non_evictable_entries; + //! Used to create buffer pool reservation on entries creation. + BufferPool &buffer_pool; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/optimistic_data_writer.hpp b/src/duckdb/src/include/duckdb/storage/optimistic_data_writer.hpp index dca2c9b1b..9d8e8499b 100644 --- a/src/duckdb/src/include/duckdb/storage/optimistic_data_writer.hpp +++ b/src/duckdb/src/include/duckdb/storage/optimistic_data_writer.hpp @@ -9,6 +9,7 @@ #pragma once #include "duckdb/storage/table/row_group_collection.hpp" +#include "duckdb/common/set.hpp" namespace duckdb { class PartialBlockManager; @@ -17,9 +18,11 @@ struct OptimisticWriteCollection { ~OptimisticWriteCollection(); shared_ptr collection; - idx_t last_flushed = 0; + set unflushed_row_groups; idx_t complete_row_groups = 0; vector> partial_block_managers; + + void MergeStorage(OptimisticWriteCollection &collection); }; enum class OptimisticWritePartialManagers { PER_COLUMN, GLOBAL }; @@ -36,8 +39,8 @@ class OptimisticDataWriter { OptimisticWritePartialManagers type = OptimisticWritePartialManagers::PER_COLUMN); //! Write a new row group to disk (if possible) void WriteNewRowGroup(OptimisticWriteCollection &row_groups); - //! Write the last row group of a collection to disk - void WriteLastRowGroup(OptimisticWriteCollection &row_groups); + //! Write any unflushed row groups of a collection to disk + void WriteUnflushedRowGroups(OptimisticWriteCollection &row_groups); //! Final flush of the optimistic writer - fully flushes the partial block manager void FinalFlush(); //! Merge the partially written blocks from one optimistic writer into another diff --git a/src/duckdb/src/include/duckdb/storage/segment/uncompressed.hpp b/src/duckdb/src/include/duckdb/storage/segment/uncompressed.hpp index 763a0d067..d28d56a93 100644 --- a/src/duckdb/src/include/duckdb/storage/segment/uncompressed.hpp +++ b/src/duckdb/src/include/duckdb/storage/segment/uncompressed.hpp @@ -30,6 +30,13 @@ struct ValidityUncompressed { public: static CompressionFunction GetFunction(PhysicalType data_type); static void AlignedScan(data_ptr_t input, idx_t input_start, Vector &result, idx_t scan_count); + + //! ANDs scan_count validity bits from input (starting at input_start) into the result validity mask + //! (starting at result_offset). If a bit in the result is already invalid (0), it remains invalid + //! regardless of the input bit value - i.e., the operation is result[i] &= input[i]. + //! This function should be used, as the name suggests, if the starting points are unaligned relative to + //! ValidityMask::BITS_PER_VALUE, otherwise AlignedScan should be used (however this function will + //! still work). static void UnalignedScan(data_ptr_t input, idx_t input_size, idx_t input_start, Vector &result, idx_t result_offset, idx_t scan_count); diff --git a/src/duckdb/src/include/duckdb/storage/single_file_block_manager.hpp b/src/duckdb/src/include/duckdb/storage/single_file_block_manager.hpp index 7a2dce826..bfcf064b3 100644 --- a/src/duckdb/src/include/duckdb/storage/single_file_block_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/single_file_block_manager.hpp @@ -38,6 +38,8 @@ struct EncryptionOptions { uint32_t key_length = MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH; //! User key pointer (to StorageOptions) shared_ptr user_key; + //! Version of duckdb-encryption + EncryptionTypes::EncryptionVersion encryption_version = EncryptionTypes::NONE; }; struct StorageManagerOptions { @@ -156,6 +158,8 @@ class SingleFileBlockManager : public BlockManager { static void StoreEncryptedCanary(AttachedDatabase &db, MainHeader &main_header, const string &key_id); static void StoreDBIdentifier(MainHeader &main_header, const data_ptr_t db_identifier); void StoreEncryptionMetadata(MainHeader &main_header) const; + template + static void WriteEncryptionData(MemoryStream &stream, const T &val); //! Check and adding Encryption Keys void CheckAndAddEncryptionKey(MainHeader &main_header, string &user_key); @@ -174,6 +178,8 @@ class SingleFileBlockManager : public BlockManager { void AddStorageVersionTag(); block_id_t GetFreeBlockIdInternal(FreeBlockType type); + //! Adds a free block to the free_list, returns true if it was added to the regular free_list + bool AddFreeBlock(unique_lock &lock, block_id_t block_id); private: AttachedDatabase &db; @@ -208,6 +214,6 @@ class SingleFileBlockManager : public BlockManager { //! The storage manager options StorageManagerOptions options; //! Lock for performing various operations in the single file block manager - mutex block_lock; + mutex single_file_block_lock; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp b/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp index 6b88247d0..925dc0341 100644 --- a/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp @@ -66,10 +66,7 @@ class StandardBufferManager : public BufferManager { DUCKDB_API BufferHandle Allocate(MemoryTag tag, idx_t block_size, bool can_destroy = true) final; DUCKDB_API BufferHandle Allocate(MemoryTag tag, BlockManager *block_manager, bool can_destroy = true) final; - //! Reallocate an in-memory buffer that is pinned. - void ReAllocate(shared_ptr &handle, idx_t block_size) final; BufferHandle Pin(shared_ptr &handle) final; - BufferHandle Pin(const QueryContext &context, shared_ptr &handle) final; void Prefetch(vector> &handles) final; @@ -96,6 +93,9 @@ class StandardBufferManager : public BufferManager { DUCKDB_API Allocator &GetBufferAllocator() final; + const DatabaseInstance &GetDatabase() const override { + return db; + } DatabaseInstance &GetDatabase() override { return db; } @@ -143,7 +143,7 @@ class StandardBufferManager : public BufferManager { //! Get the path of the temporary buffer string GetTemporaryPath(block_id_t id); - void DeleteTemporaryFile(BlockHandle &block) final; + void DeleteTemporaryFile(BlockMemory &memory) final; void RequireTemporaryDirectory(); @@ -163,6 +163,8 @@ class StandardBufferManager : public BufferManager { void BatchRead(vector> &handles, const map &load_map, block_id_t first_block, block_id_t last_block); + bool EncryptTemporaryFiles(); + protected: // These are stored here because temp_directory creation is lazy // so we need to store information related to the temporary directory before it's created diff --git a/src/duckdb/src/include/duckdb/storage/statistics/base_statistics.hpp b/src/duckdb/src/include/duckdb/storage/statistics/base_statistics.hpp index 237ddec7e..203fdef6e 100644 --- a/src/duckdb/src/include/duckdb/storage/statistics/base_statistics.hpp +++ b/src/duckdb/src/include/duckdb/storage/statistics/base_statistics.hpp @@ -89,7 +89,7 @@ class BaseStatistics { void Set(StatsInfo info); void CombineValidity(const BaseStatistics &left, const BaseStatistics &right); - void CopyValidity(BaseStatistics &stats); + void CopyValidity(const BaseStatistics &stats); //! Set that the CURRENT level can have null values //! Note that this is not correct for nested types unless this information is propagated in a different manner //! Use Set(StatsInfo::CAN_HAVE_NULL_VALUES) in the general case diff --git a/src/duckdb/src/include/duckdb/storage/statistics/geometry_stats.hpp b/src/duckdb/src/include/duckdb/storage/statistics/geometry_stats.hpp index 78f7608d3..2adf308d6 100644 --- a/src/duckdb/src/include/duckdb/storage/statistics/geometry_stats.hpp +++ b/src/duckdb/src/include/duckdb/storage/statistics/geometry_stats.hpp @@ -75,6 +75,69 @@ class GeometryTypeSet { } } + //! Check if only the given geometry and vertex type is present + //! (all others are absent) + bool HasOnly(GeometryType geom_type, VertexType vert_type) const { + const auto vert_idx = static_cast(vert_type); + const auto geom_idx = static_cast(geom_type); + D_ASSERT(vert_idx < VERT_TYPES); + D_ASSERT(geom_idx < PART_TYPES); + for (uint8_t v_idx = 0; v_idx < VERT_TYPES; v_idx++) { + for (uint8_t g_idx = 1; g_idx < PART_TYPES; g_idx++) { + if (v_idx == vert_idx && g_idx == geom_idx) { + if (!(sets[v_idx] & (1 << g_idx))) { + return false; + } + } else { + if (sets[v_idx] & (1 << g_idx)) { + return false; + } + } + } + } + return true; + } + + bool HasSingleType() const { + idx_t type_count = 0; + for (uint8_t v_idx = 0; v_idx < VERT_TYPES; v_idx++) { + for (uint8_t g_idx = 1; g_idx < PART_TYPES; g_idx++) { + if (sets[v_idx] & (1 << g_idx)) { + type_count++; + if (type_count > 1) { + return false; + } + } + } + } + return type_count == 1; + } + + bool TryGetSingleType(GeometryType &geom_type, VertexType &vert_type) const { + auto result_geom = GeometryType::INVALID; + auto result_vert = VertexType::XY; + auto result_found = false; + + for (uint8_t v_idx = 0; v_idx < VERT_TYPES; v_idx++) { + for (uint8_t g_idx = 1; g_idx < PART_TYPES; g_idx++) { + if (sets[v_idx] & (1 << g_idx)) { + if (result_found) { + // Multiple types found + return false; + } + result_found = true; + result_geom = static_cast(g_idx); + result_vert = static_cast(v_idx); + } + } + } + if (result_found) { + geom_type = result_geom; + vert_type = result_vert; + } + return result_found; + } + void AddWKBType(int32_t wkb_type) { const auto vert_idx = static_cast((wkb_type / 1000) % 10); const auto geom_idx = static_cast(wkb_type % 1000); @@ -100,23 +163,85 @@ class GeometryTypeSet { uint8_t sets[VERT_TYPES]; }; +class GeometryStatsFlags { +public: + // There are two types of "empty" + // 1. Empty geometry: A geometry that contains no vertices (e.g., POINT EMPTY) + // 2. Empty part: A geometry that contains at least one empty geometry (e.g., MULTIPOINT(POINT EMPTY, POINT(1 2))) + + static GeometryStatsFlags Unknown() { + GeometryStatsFlags flags; + flags.flags = 0xF; // All bits set + return flags; + } + + static GeometryStatsFlags Empty() { + GeometryStatsFlags flags; + flags.flags = 0x0; // No bits set + return flags; + } + void Clear() { + flags = 0x0; + } + bool HasEmptyGeometry() const { + return (flags & HAS_EMPTY_GEOM) != 0; + } + bool HasNonEmptyGeometry() const { + return (flags & HAS_NON_EMPTY_GEOM) != 0; + } + bool HasEmptyPart() const { + return (flags & HAS_EMPTY_PART) != 0; + } + bool HasNonEmptyPart() const { + return (flags & HAS_NON_EMPTY_PART) != 0; + } + void SetHasEmptyGeometry() { + flags |= HAS_EMPTY_GEOM; + } + void SetHasNonEmptyGeometry() { + flags |= HAS_NON_EMPTY_GEOM; + } + void SetHasEmptyPart() { + flags |= HAS_EMPTY_PART; + } + void SetHasNonEmptyPart() { + flags |= HAS_NON_EMPTY_PART; + } + + void Merge(const GeometryStatsFlags &other) { + flags |= other.flags; + } + + uint8_t flags; + +private: + static constexpr auto HAS_EMPTY_GEOM = 0x1; + static constexpr auto HAS_NON_EMPTY_GEOM = 0x2; + static constexpr auto HAS_EMPTY_PART = 0x4; + static constexpr auto HAS_NON_EMPTY_PART = 0x8; +}; + struct GeometryStatsData { GeometryTypeSet types; GeometryExtent extent; + GeometryStatsFlags flags; void SetEmpty() { types = GeometryTypeSet::Empty(); extent = GeometryExtent::Empty(); + flags = GeometryStatsFlags::Empty(); } void SetUnknown() { types = GeometryTypeSet::Unknown(); extent = GeometryExtent::Unknown(); + flags = GeometryStatsFlags::Unknown(); } void Merge(const GeometryStatsData &other) { types.Merge(other.types); extent.Merge(other.extent); + flags.Merge(other.flags); } void Update(const string_t &geom_blob) { @@ -125,7 +250,21 @@ struct GeometryStatsData { types.Add(type_info.first, type_info.second); // Update extent - Geometry::GetExtent(geom_blob, extent); + bool has_any_empty = false; + const auto vert_count = Geometry::GetExtent(geom_blob, extent, has_any_empty); + + // Update flags + if (has_any_empty) { + flags.SetHasEmptyPart(); + } else { + flags.SetHasNonEmptyPart(); + } + + if (vert_count == 0) { + flags.SetHasEmptyGeometry(); + } else { + flags.SetHasNonEmptyGeometry(); + } } }; @@ -152,8 +291,9 @@ struct GeometryStats { DUCKDB_API static const GeometryExtent &GetExtent(const BaseStatistics &stats); DUCKDB_API static GeometryTypeSet &GetTypes(BaseStatistics &stats); DUCKDB_API static const GeometryTypeSet &GetTypes(const BaseStatistics &stats); + DUCKDB_API static GeometryStatsFlags &GetFlags(BaseStatistics &stats); + DUCKDB_API static const GeometryStatsFlags &GetFlags(const BaseStatistics &stats); -private: static GeometryStatsData &GetDataUnsafe(BaseStatistics &stats); static const GeometryStatsData &GetDataUnsafe(const BaseStatistics &stats); }; diff --git a/src/duckdb/src/include/duckdb/storage/statistics/variant_stats.hpp b/src/duckdb/src/include/duckdb/storage/statistics/variant_stats.hpp index e2cbfae94..3581012ad 100644 --- a/src/duckdb/src/include/duckdb/storage/statistics/variant_stats.hpp +++ b/src/duckdb/src/include/duckdb/storage/statistics/variant_stats.hpp @@ -2,6 +2,7 @@ #include "duckdb/common/types/variant.hpp" #include "duckdb/common/types/selection_vector.hpp" +#include "duckdb/storage/storage_index.hpp" namespace duckdb { class BaseStatistics; @@ -25,6 +26,8 @@ struct VariantStatsData { struct VariantShreddedStats { public: DUCKDB_API static bool IsFullyShredded(const BaseStatistics &stats); + DUCKDB_API static optional_ptr FindChildStats(const BaseStatistics &stats, + const VariantPathComponent &component); }; //! VARIANT as a type can hold arbitrarily typed values within the same column. @@ -32,6 +35,10 @@ struct VariantShreddedStats { //! values. And for those values we store them separately from the rest of the values, in a structured way (like you //! would store any other column). struct VariantStats { +public: + static constexpr idx_t TYPED_VALUE_INDEX = 0; + static constexpr idx_t UNTYPED_VALUE_INDEX = 1; + public: DUCKDB_API static void Construct(BaseStatistics &stats); @@ -47,6 +54,14 @@ struct VariantStats { DUCKDB_API static const BaseStatistics &GetUnshreddedStats(const BaseStatistics &stats); DUCKDB_API static BaseStatistics &GetUnshreddedStats(BaseStatistics &stats); + //! Returns the typed_value stats of a shredded stats entry + DUCKDB_API static const BaseStatistics &GetTypedStats(const BaseStatistics &stats); + DUCKDB_API static const BaseStatistics &GetTypedStats(const BaseStatistics &&stats) = delete; + + //! Returns the untyped_value_index stats of a shredded stats entry - if there is any + DUCKDB_API static optional_ptr GetUntypedStats(const BaseStatistics &stats); + DUCKDB_API static optional_ptr GetUntypedStats(const BaseStatistics &&stats) = delete; + DUCKDB_API static void SetUnshreddedStats(BaseStatistics &stats, unique_ptr new_stats); DUCKDB_API static void SetUnshreddedStats(BaseStatistics &stats, const BaseStatistics &new_stats); DUCKDB_API static void MarkAsNotShredded(BaseStatistics &stats); @@ -54,7 +69,7 @@ struct VariantStats { public: //! Stats related to the 'shredded' column, which holds all structured data created during shredding //! Returns the LogicalType that represents the shredding as a single DuckDB LogicalType (i.e STRUCT(col1 VARCHAR)) - DUCKDB_API LogicalType GetShreddedStructuredType(const BaseStatistics &stats); + DUCKDB_API static LogicalType GetShreddedStructuredType(const BaseStatistics &stats); DUCKDB_API static void CreateShreddedStats(BaseStatistics &stats, const LogicalType &shredded_type); DUCKDB_API static bool IsShredded(const BaseStatistics &stats); DUCKDB_API static const BaseStatistics &GetShreddedStats(const BaseStatistics &stats); @@ -63,8 +78,10 @@ struct VariantStats { DUCKDB_API static void SetShreddedStats(BaseStatistics &stats, unique_ptr new_stats); DUCKDB_API static void SetShreddedStats(BaseStatistics &stats, const BaseStatistics &new_stats); - DUCKDB_API static bool MergeShredding(BaseStatistics &stats, const BaseStatistics &other, + DUCKDB_API static bool MergeShredding(const BaseStatistics &stats, const BaseStatistics &other, BaseStatistics &new_stats); + DUCKDB_API static unique_ptr WrapExtractedFieldAsVariant(const BaseStatistics &base_variant, + const BaseStatistics &extracted_field); public: DUCKDB_API static void Serialize(const BaseStatistics &stats, Serializer &serializer); @@ -75,6 +92,8 @@ struct VariantStats { DUCKDB_API static void Merge(BaseStatistics &stats, const BaseStatistics &other); DUCKDB_API static void Verify(const BaseStatistics &stats, Vector &vector, const SelectionVector &sel, idx_t count); DUCKDB_API static void Copy(BaseStatistics &stats, const BaseStatistics &other); + DUCKDB_API static unique_ptr PushdownExtract(const BaseStatistics &stats, + const StorageIndex &index); private: static VariantStatsData &GetDataUnsafe(BaseStatistics &stats); diff --git a/src/duckdb/src/include/duckdb/storage/storage_extension.hpp b/src/duckdb/src/include/duckdb/storage/storage_extension.hpp index 8f55d9b7c..62b887cd1 100644 --- a/src/duckdb/src/include/duckdb/storage/storage_extension.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_extension.hpp @@ -44,10 +44,13 @@ class StorageExtension { virtual void OnCheckpointEnd(AttachedDatabase &db, CheckpointOptions checkpoint_options) { } + + static optional_ptr Find(const DBConfig &config, const string &extension_name); + static void Register(DBConfig &config, const string &extension_name, shared_ptr extension); }; struct OpenFileStorageExtension { - static unique_ptr Create(); + static shared_ptr Create(); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/storage_index.hpp b/src/duckdb/src/include/duckdb/storage/storage_index.hpp index 09aec8e1c..6034fb0c0 100644 --- a/src/duckdb/src/include/duckdb/storage/storage_index.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_index.hpp @@ -19,13 +19,11 @@ enum class StorageIndexType : uint8_t { FULL_READ, PUSHDOWN_EXTRACT }; struct StorageIndex { public: - StorageIndex() : index(COLUMN_IDENTIFIER_ROW_ID), index_type(StorageIndexType::FULL_READ) { - } - explicit StorageIndex(idx_t index) : index(index), index_type(StorageIndexType::FULL_READ) { - } - StorageIndex(idx_t index, vector child_indexes_p) - : index(index), index_type(StorageIndexType::FULL_READ), child_indexes(std::move(child_indexes_p)) { - } + StorageIndex(); + explicit StorageIndex(idx_t index); + explicit StorageIndex(const string &field); + StorageIndex(idx_t index, vector child_indexes_p); + StorageIndex(const string &field, vector child_indexes_p); inline bool operator==(const StorageIndex &rhs) const { return index == rhs.index; @@ -38,71 +36,36 @@ struct StorageIndex { } public: - static StorageIndex FromColumnIndex(const ColumnIndex &column_id) { - vector result; - for (auto &child_id : column_id.GetChildIndexes()) { - result.push_back(StorageIndex::FromColumnIndex(child_id)); - } - auto storage_index = StorageIndex(column_id.GetPrimaryIndex(), std::move(result)); - if (column_id.HasType()) { - storage_index.SetType(column_id.GetType()); - } - if (column_id.IsPushdownExtract()) { - storage_index.SetPushdownExtract(); - } - return storage_index; - } + static StorageIndex FromColumnIndex(const ColumnIndex &column_id); public: - idx_t GetPrimaryIndex() const { - return index; - } - PhysicalIndex ToPhysical() const { - return PhysicalIndex(index); - } - bool HasType() const { - return type.id() != LogicalTypeId::INVALID; - } - const LogicalType &GetType() const { - return type; - } - bool HasChildren() const { - return !child_indexes.empty(); - } - idx_t ChildIndexCount() const { - return child_indexes.size(); - } - const StorageIndex &GetChildIndex(idx_t idx) const { - return child_indexes[idx]; - } - StorageIndex &GetChildIndex(idx_t idx) { - return child_indexes[idx]; - } - const vector &GetChildIndexes() const { - return child_indexes; - } - void AddChildIndex(StorageIndex new_index) { - this->child_indexes.push_back(std::move(new_index)); - } - void SetType(const LogicalType &type_information) { - type = type_information; - } - void SetPushdownExtract() { - D_ASSERT(!IsPushdownExtract()); - index_type = StorageIndexType::PUSHDOWN_EXTRACT; - } - bool IsPushdownExtract() const { - return index_type == StorageIndexType::PUSHDOWN_EXTRACT; - } - void SetIndex(idx_t new_index) { - index = new_index; - } - bool IsRowIdColumn() const { - return index == DConstants::INVALID_INDEX; - } + bool HasPrimaryIndex() const; + idx_t GetPrimaryIndex() const; + const string &GetFieldName() const; + PhysicalIndex ToPhysical() const; + bool HasType() const; + const LogicalType &GetScanType() const; + const LogicalType &GetType() const; + bool HasChildren() const; + idx_t ChildIndexCount() const; + const StorageIndex &GetChildIndex(idx_t idx) const; + StorageIndex &GetChildIndex(idx_t idx); + const vector &GetChildIndexes() const; + void AddChildIndex(StorageIndex new_index); + void SetType(const LogicalType &type_information); + void SetPushdownExtract(); + bool IsPushdownExtract() const; + void SetIndex(idx_t new_index); + bool IsRowIdColumn() const; + + void Serialize(Serializer &serializer) const; + static StorageIndex Deserialize(Deserializer &deserializer); private: + bool has_index = true; idx_t index; + string field; + LogicalType type = LogicalType::INVALID; StorageIndexType index_type; vector child_indexes; diff --git a/src/duckdb/src/include/duckdb/storage/storage_info.hpp b/src/duckdb/src/include/duckdb/storage/storage_info.hpp index f919bac33..cceff805a 100644 --- a/src/duckdb/src/include/duckdb/storage/storage_info.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_info.hpp @@ -12,7 +12,6 @@ #include "duckdb/common/limits.hpp" #include "duckdb/common/string.hpp" #include "duckdb/common/vector_size.hpp" -#include "duckdb/common/encryption_state.hpp" namespace duckdb { @@ -33,8 +32,13 @@ class QueryContext; //! The default block header size for encrypted blocks. #define DEFAULT_ENCRYPTION_BLOCK_HEADER_SIZE 40ULL //! The configurable block allocation size. + +// Configurable block allocation size #ifndef DUCKDB_BLOCK_HEADER_STORAGE_SIZE -#define DUCKDB_BLOCK_HEADER_STORAGE_SIZE DEFAULT_BLOCK_HEADER_STORAGE_SIZE +#define DUCKDB_BLOCK_HEADER_STORAGE_SIZE DEFAULT_BLOCK_HEADER_STORAGE_SIZE +#endif + +#ifndef DEFAULT_ENCRYPTED_BUFFER_HEADER_SIZE #define DEFAULT_ENCRYPTED_BUFFER_HEADER_SIZE 32ULL #endif @@ -96,6 +100,8 @@ class MainHeader { uint64_t version_number; //! The set of flags used by the database. uint64_t flags[FLAG_COUNT]; + //! Encryption version + uint8_t encryption_version; //! The length of the unique database identifier. static constexpr idx_t DB_IDENTIFIER_LEN = 16; @@ -104,7 +110,9 @@ class MainHeader { //! The canary is a known plaintext for detecting wrong keys early. static constexpr idx_t CANARY_BYTE_SIZE = 8; //! Nonce, IV (nonce + counter) and tag length - static constexpr uint64_t AES_NONCE_LEN = 16; + static constexpr uint64_t AES_NONCE_LEN = 12; + static constexpr uint64_t AES_COUNTER_BYTES = 4; + static constexpr uint64_t AES_NONCE_LEN_DEPRECATED = 16; static constexpr uint64_t AES_IV_LEN = 16; static constexpr uint64_t AES_TAG_LEN = 16; @@ -123,14 +131,21 @@ class MainHeader { void SetEncrypted() { flags[0] |= MainHeader::ENCRYPTED_DATABASE_FLAG; } + void SetEncryptionVersion(uint8_t version) { + encryption_version = version; + } void SetEncryptionMetadata(data_ptr_t source) { memset(encryption_metadata, 0, ENCRYPTION_METADATA_LEN); memcpy(encryption_metadata, source, ENCRYPTION_METADATA_LEN); } - EncryptionTypes::CipherType GetEncryptionCipher() { - return static_cast(encryption_metadata[2]); + uint8_t GetEncryptionCipher() const { + return encryption_metadata[2]; + } + + uint8_t GetEncryptionVersion() const { + return encryption_metadata[3]; } void SetDBIdentifier(data_ptr_t source) { @@ -143,10 +158,28 @@ class MainHeader { memcpy(encrypted_canary, source, CANARY_BYTE_SIZE); } + void SetCanaryIV(data_ptr_t source) { + memset(canary_iv, 0, AES_NONCE_LEN); + memcpy(canary_iv, source, AES_NONCE_LEN); + } + + void SetCanaryTag(data_ptr_t source) { + memset(canary_tag, 0, AES_TAG_LEN); + memcpy(canary_tag, source, AES_TAG_LEN); + } + data_ptr_t GetDBIdentifier() { return db_identifier; } + data_ptr_t GetIV() { + return canary_iv; + } + + data_ptr_t GetTag() { + return canary_tag; + } + static bool CompareDBIdentifiers(const data_ptr_t db_identifier_1, const data_ptr_t db_identifier_2) { for (idx_t i = 0; i < DB_IDENTIFIER_LEN; i++) { if (db_identifier_1[i] != db_identifier_2[i]) { @@ -170,6 +203,8 @@ class MainHeader { //! The unique database identifier and optional encryption salt. data_t db_identifier[DB_IDENTIFIER_LEN]; data_t encrypted_canary[CANARY_BYTE_SIZE]; + data_t canary_iv[AES_NONCE_LEN]; + data_t canary_tag[AES_TAG_LEN]; }; //! The DatabaseHeader contains information about the current state of the database. Every storage file has two diff --git a/src/duckdb/src/include/duckdb/storage/storage_manager.hpp b/src/duckdb/src/include/duckdb/storage/storage_manager.hpp index b6e0fda94..54517d320 100644 --- a/src/duckdb/src/include/duckdb/storage/storage_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_manager.hpp @@ -49,7 +49,7 @@ class StorageCommitState { //! StorageManager is responsible for managing the physical storage of a persistent database. class StorageManager { public: - StorageManager(AttachedDatabase &db, string path, const AttachOptions &options); + StorageManager(AttachedDatabase &db, string path, AttachOptions &options); virtual ~StorageManager(); public: @@ -71,6 +71,10 @@ class StorageManager { bool HasWAL() const; void AddWALSize(idx_t size); void SetWALSize(idx_t size); + //! Gets the number of WAL entries since last checkpoint + idx_t GetWALEntriesCount() const; + void ResetWALEntriesCount(); + void IncrementWALEntriesCount(); //! Gets the WAL of the StorageManager, or nullptr, if there is no WAL. optional_ptr GetWAL(); //! Write that we started a checkpoint to the WAL if there is one - returns whether or not there is a WAL @@ -128,10 +132,19 @@ class StorageManager { } storage_options.encryption_cipher = cipher_p; } + + void SetEncryptionVersion(EncryptionTypes::EncryptionVersion version) { + storage_options.encryption_version = version; + } + bool IsEncrypted() const { return storage_options.encryption; } + EncryptionTypes::EncryptionVersion GetEncryptionVersion() const { + return storage_options.encryption_version; + } + protected: virtual void LoadDatabase(QueryContext context) = 0; @@ -156,6 +169,7 @@ class StorageManager { //! Estimated size of changes for determining automatic checkpointing on in-memory databases and databases without a //! WAL. atomic wal_size; + atomic wal_entries_count; //! Storage options passed in through configuration StorageOptions storage_options; @@ -176,9 +190,9 @@ class StorageManager { class SingleFileStorageManager : public StorageManager { public: SingleFileStorageManager() = delete; - SingleFileStorageManager(AttachedDatabase &db, string path, const AttachOptions &options); + SingleFileStorageManager(AttachedDatabase &db, string path, AttachOptions &options); - //! The BlockManager to read from and write to blocks (meta data and data). + //! The BlockManager to read from and write to blocks, both for the metadata and the data itself. unique_ptr block_manager; //! The table I/O manager. unique_ptr table_io_manager; diff --git a/src/duckdb/src/include/duckdb/storage/storage_options.hpp b/src/duckdb/src/include/duckdb/storage/storage_options.hpp index 4cf1f539b..dc68c4ad9 100644 --- a/src/duckdb/src/include/duckdb/storage/storage_options.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_options.hpp @@ -36,8 +36,11 @@ struct StorageOptions { //! encryption key //! FIXME: change to a unique_ptr in the future shared_ptr user_key; + //! encryption version (set default to 1) + EncryptionTypes::EncryptionVersion encryption_version = EncryptionTypes::NONE; - void Initialize(const unordered_map &options); + void SetEncryptionVersion(string &storage_version_user_provided); + void Initialize(unordered_map &options); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp b/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp index 286c97fdf..52ed376c4 100644 --- a/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp +++ b/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp @@ -127,7 +127,7 @@ struct UncompressedStringStorage { auto end = handle.Ptr() + *dictionary_end; #ifdef DEBUG - GetDictionary(segment, handle).Verify(segment.GetBlockManager().GetBlockSize()); + GetDictionary(segment, handle).Verify(segment.GetBlockSize()); #endif // Unknown string, continue // non-null value, check if we can fit it within the block @@ -136,8 +136,7 @@ struct UncompressedStringStorage { // determine whether or not we have space in the block for this string bool use_overflow_block = false; idx_t required_space = string_length; - if (DUCKDB_UNLIKELY(required_space >= - StringUncompressed::GetStringBlockLimit(segment.GetBlockManager().GetBlockSize()))) { + if (DUCKDB_UNLIKELY(required_space >= StringUncompressed::GetStringBlockLimit(segment.GetBlockSize()))) { // string exceeds block limit, store in overflow block and only write a marker here required_space = BIG_STRING_MARKER_SIZE; use_overflow_block = true; @@ -168,7 +167,7 @@ struct UncompressedStringStorage { // note: for overflow strings we write negative value // dictionary_size is an uint32_t value, so we can cast up. - D_ASSERT(NumericCast(*dictionary_size) <= segment.GetBlockManager().GetBlockSize()); + D_ASSERT(NumericCast(*dictionary_size) <= segment.GetBlockSize()); result_data[target_idx] = -NumericCast((*dictionary_size)); } else { // string fits in block, append to dictionary and increment dictionary position @@ -180,13 +179,13 @@ struct UncompressedStringStorage { memcpy(dict_pos, source_data[source_idx].GetData(), string_length); // dictionary_size is an uint32_t value, so we can cast up. - D_ASSERT(NumericCast(*dictionary_size) <= segment.GetBlockManager().GetBlockSize()); + D_ASSERT(NumericCast(*dictionary_size) <= segment.GetBlockSize()); // Place the dictionary offset into the set of vectors. result_data[target_idx] = NumericCast(*dictionary_size); } - D_ASSERT(RemainingSpace(segment, handle) <= segment.GetBlockManager().GetBlockSize()); + D_ASSERT(RemainingSpace(segment, handle) <= segment.GetBlockSize()); #ifdef DEBUG - GetDictionary(segment, handle).Verify(segment.GetBlockManager().GetBlockSize()); + GetDictionary(segment, handle).Verify(segment.GetBlockSize()); #endif } segment.count += count; @@ -220,7 +219,7 @@ struct UncompressedStringStorage { inline static string_t FetchStringFromDict(ColumnSegment &segment, uint32_t dict_end_offset, Vector &result, data_ptr_t base_ptr, int32_t dict_offset, uint32_t string_length) { - D_ASSERT(dict_offset <= NumericCast(segment.GetBlockManager().GetBlockSize())); + D_ASSERT(dict_offset <= NumericCast(segment.GetBlockSize())); if (DUCKDB_LIKELY(dict_offset >= 0)) { // regular string - fetch from dictionary auto dict_end = base_ptr + dict_end_offset; diff --git a/src/duckdb/src/include/duckdb/storage/table/array_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/array_column_data.hpp index 79b2d007c..f9b15b0f1 100644 --- a/src/duckdb/src/include/duckdb/storage/table/array_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/array_column_data.hpp @@ -52,7 +52,8 @@ class ArrayColumnData : public ColumnData { unique_ptr CreateCheckpointState(const RowGroup &row_group, PartialBlockManager &partial_block_manager) override; - unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info) override; + unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &old_stats) override; bool IsPersistent() override; bool HasAnyChanges() const override; @@ -67,6 +68,8 @@ class ArrayColumnData : public ColumnData { void SetValidityData(shared_ptr validity); void SetChildData(shared_ptr child_column); + const BaseStatistics &GetChildStats(const ColumnData &child) const override; + protected: //! The child-column of the list shared_ptr child_column; diff --git a/src/duckdb/src/include/duckdb/storage/table/column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/column_data.hpp index 53f309ce4..ad291434f 100644 --- a/src/duckdb/src/include/duckdb/storage/table/column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/column_data.hpp @@ -104,6 +104,9 @@ class ColumnData : public enable_shared_from_this { D_ASSERT(HasParent()); return *parent; } + + virtual const BaseStatistics &GetChildStats(const ColumnData &child) const; + const LogicalType &GetType() const { return type; } @@ -175,7 +178,11 @@ class ColumnData : public enable_shared_from_this { virtual unique_ptr CreateCheckpointState(const RowGroup &row_group, PartialBlockManager &partial_block_manager); - virtual unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info); + //! If this is a nested column, "stats" are the corresponding statistics from the parent column + //! Otherwise, "stats" == this->statistics->stats + unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info); + virtual unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &stats); virtual void CheckpointScan(ColumnSegment &segment, ColumnScanState &state, idx_t count, Vector &scan_vector) const; @@ -202,6 +209,7 @@ class ColumnData : public enable_shared_from_this { void MergeStatistics(const BaseStatistics &other); void MergeIntoStatistics(BaseStatistics &other); unique_ptr GetStatistics() const; + const BaseStatistics &GetStatisticsRef() const; protected: //! Append a transient segment @@ -243,10 +251,10 @@ class ColumnData : public enable_shared_from_this { unique_ptr updates; //! The lock for the stats mutable mutex stats_lock; - //! The stats of the root segment - unique_ptr stats; //! Total transient allocation size atomic allocation_size; + //! The stats of the root segment + unique_ptr stats; private: //! Whether or not this column data belongs to a main table or if it is transaction local @@ -270,6 +278,69 @@ class ColumnData : public enable_shared_from_this { } }; +enum class ExtraPersistentColumnDataType : uint8_t { + INVALID = 0, + VARIANT = 1, + GEOMETRY = 2, +}; + +class ExtraPersistentColumnData { +public: + ExtraPersistentColumnDataType GetType() const { + return type; + } + + virtual ~ExtraPersistentColumnData() = default; + + template + TARGET &Cast() { + D_ASSERT(type == TARGET::TYPE); + DynamicCastCheck(this); + return reinterpret_cast(*this); + } + template + const TARGET &Cast() const { + D_ASSERT(type == TARGET::TYPE); + DynamicCastCheck(this); + return reinterpret_cast(*this); + } + + void Serialize(Serializer &serializer) const; + static unique_ptr Deserialize(Deserializer &deserializer); + +protected: + explicit ExtraPersistentColumnData(ExtraPersistentColumnDataType type_p) : type(type_p) { + } + +private: + ExtraPersistentColumnDataType type; +}; + +class VariantPersistentColumnData final : public ExtraPersistentColumnData { +public: + static constexpr auto TYPE = ExtraPersistentColumnDataType::VARIANT; + VariantPersistentColumnData() : ExtraPersistentColumnData(TYPE) { + } + explicit VariantPersistentColumnData(const LogicalType &storage_type) + : ExtraPersistentColumnData(TYPE), logical_type(storage_type) { + } + + LogicalType logical_type; +}; + +class GeometryPersistentColumnData final : public ExtraPersistentColumnData { +public: + static constexpr auto TYPE = ExtraPersistentColumnDataType::GEOMETRY; + GeometryPersistentColumnData() : ExtraPersistentColumnData(TYPE) { + } + GeometryPersistentColumnData(GeometryType type, VertexType vert) + : ExtraPersistentColumnData(TYPE), geom_type(type), vert_type(vert) { + } + + GeometryType geom_type = GeometryType::INVALID; + VertexType vert_type = VertexType::XY; +}; + struct PersistentColumnData { public: explicit PersistentColumnData(const LogicalType &logical_type); @@ -288,15 +359,15 @@ struct PersistentColumnData { void DeserializeField(Deserializer &deserializer, field_id_t field_idx, const char *field_name, const LogicalType &type); bool HasUpdates() const; - void SetVariantShreddedType(const LogicalType &shredded_type); public: - PhysicalType physical_type; - LogicalTypeId logical_type_id; + LogicalType logical_type; vector pointers; vector child_columns; bool has_updates = false; - LogicalType variant_shredded_type; + + //! Extra persistent data for specific column types + unique_ptr extra_data; }; struct PersistentRowGroupData { diff --git a/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp b/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp index ce75200b4..3f5750bad 100644 --- a/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp @@ -110,11 +110,9 @@ class ColumnSegment : public SegmentBase { return block_id; } - //! Returns the block manager handling this segment. For transient segments, this might be the temporary block - //! manager. Later, we possibly convert this (transient) segment to a persistent segment. In that case, there - //! exists another block manager handling the ColumnData, of which this segment is a part. - BlockManager &GetBlockManager() const { - return block->block_manager; + //! Returns the size of the underlying block of the segment. It is size is the size available for usage on a block. + idx_t GetBlockSize() const { + return block->GetBlockSize(); } idx_t GetBlockOffset() { diff --git a/src/duckdb/src/include/duckdb/storage/table/data_table_info.hpp b/src/duckdb/src/include/duckdb/storage/table/data_table_info.hpp index b0b9a2604..e89ce6f4a 100644 --- a/src/duckdb/src/include/duckdb/storage/table/data_table_info.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/data_table_info.hpp @@ -39,9 +39,8 @@ struct DataTableInfo { TableIndexList &GetIndexes() { return indexes; } - const vector &GetIndexStorageInfo() const { - return index_storage_infos; - } + //! Find and move out an IndexStorageInfo by name from the stored collection. + IndexStorageInfo ExtractIndexStorageInfo(const string &name); unique_ptr GetSharedLock() { return checkpoint_lock.GetSharedLock(); } diff --git a/src/duckdb/src/include/duckdb/storage/table/geo_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/geo_column_data.hpp new file mode 100644 index 000000000..d091530e7 --- /dev/null +++ b/src/duckdb/src/include/duckdb/storage/table/geo_column_data.hpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/storage/table/geo_column_data.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/storage/table/column_data.hpp" +#include "duckdb/storage/table/validity_column_data.hpp" + +namespace duckdb { + +class GeoColumnData final : public ColumnData { +public: + GeoColumnData(BlockManager &block_manager, DataTableInfo &info, idx_t column_index, LogicalType type, + ColumnDataType data_type, optional_ptr parent); + + //! The actual column data + //! The "shape" of this might differ depending on if we "shred" this column or not. + shared_ptr base_column; + + //! Shredding state of the column + GeometryType geom_type = GeometryType::INVALID; + VertexType vert_type = VertexType::XY; + +public: + idx_t GetMaxEntry() override; + + void InitializeChildScanStates(ColumnScanState &state); + + void InitializePrefetch(PrefetchState &prefetch_state, ColumnScanState &scan_state, idx_t rows) override; + void InitializeScan(ColumnScanState &state) override; + void InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) override; + + idx_t Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, + idx_t scan_count) override; + + idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count, idx_t result_offset = 0) 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 new_count) override; + idx_t Fetch(ColumnScanState &state, row_t row_id, Vector &result) override; + void FetchRow(TransactionData transaction, ColumnFetchState &state, const StorageIndex &storage_index, row_t row_id, + Vector &result, idx_t result_idx) override; + void Update(TransactionData transaction, DataTable &data_table, idx_t column_index, Vector &update_vector, + row_t *row_ids, idx_t update_count, idx_t row_group_start) override; + void UpdateColumn(TransactionData transaction, DataTable &data_table, const vector &column_path, + Vector &update_vector, row_t *row_ids, idx_t update_count, idx_t depth, + idx_t row_group_start) override; + unique_ptr GetUpdateStatistics() override; + + unique_ptr CreateCheckpointState(const RowGroup &row_group, + PartialBlockManager &partial_block_manager) override; + unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &old_stats) override; + + bool IsPersistent() override; + bool HasAnyChanges() const override; + PersistentColumnData Serialize() override; + void InitializeColumn(PersistentColumnData &column_data, BaseStatistics &target_stats) override; + + void GetColumnSegmentInfo(const QueryContext &context, idx_t row_group_index, vector col_path, + vector &result) override; + + void Verify(RowGroup &parent) override; + + void VisitBlockIds(BlockIdVisitor &visitor) const override; + +private: + static void Specialize(Vector &source, Vector &target, idx_t count, GeometryType geom_type, VertexType vert_type); + static void Reassemble(Vector &source, Vector &target, idx_t count, GeometryType geom_type, VertexType vert_type, + idx_t offset); + static void InterpretStats(BaseStatistics &source, BaseStatistics &target, GeometryType geom_type, + VertexType vert_type); +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp index 31b99e223..547d56fbb 100644 --- a/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp @@ -50,7 +50,8 @@ class ListColumnData : public ColumnData { unique_ptr CreateCheckpointState(const RowGroup &row_group, PartialBlockManager &partial_block_manager) override; - unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info) override; + unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &old_stats) override; bool IsPersistent() override; bool HasAnyChanges() const override; @@ -63,6 +64,8 @@ class ListColumnData : public ColumnData { void SetValidityData(shared_ptr validity_p); void SetChildData(shared_ptr child_column_p); + const BaseStatistics &GetChildStats(const ColumnData &child) const override; + protected: //! The child-column of the list shared_ptr child_column; diff --git a/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp b/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp index 7134e06ea..0ce1ef4e5 100644 --- a/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp @@ -38,6 +38,8 @@ struct PersistentCollectionData; class CheckpointTask; class TableIOManager; class DataTable; +class RowGroupIterationHelper; +class TableScanState; class RowGroupCollection { public: @@ -48,6 +50,7 @@ class RowGroupCollection { public: idx_t GetTotalRows() const; + idx_t GetRowGroupCount() const; Allocator &GetAllocator() const; void Initialize(PersistentCollectionData &data); @@ -70,15 +73,14 @@ class RowGroupCollection { void InitializeCreateIndexScan(CreateIndexScanState &state); void InitializeScanWithOffset(const QueryContext &context, CollectionScanState &state, const vector &column_ids, idx_t start_row, idx_t end_row); - static bool InitializeScanInRowGroup(const QueryContext &context, CollectionScanState &state, + static bool InitializeScanInRowGroup(ClientContext &context, CollectionScanState &state, RowGroupCollection &collection, SegmentNode &row_group, idx_t vector_index, idx_t max_row); void InitializeParallelScan(ParallelCollectionScanState &state); bool NextParallelScan(ClientContext &context, ParallelCollectionScanState &state, CollectionScanState &scan_state); - bool Scan(DuckTransaction &transaction, const vector &column_ids, - const std::function &fun); - bool Scan(DuckTransaction &transaction, const std::function &fun); + RowGroupIterationHelper Chunks(DuckTransaction &transaction); + RowGroupIterationHelper Chunks(DuckTransaction &transaction, const vector &column_ids); void Fetch(TransactionData transaction, DataChunk &result, const vector &column_ids, const Vector &row_identifiers, idx_t fetch_count, ColumnFetchState &state); @@ -193,4 +195,39 @@ class RowGroupCollection { bool requires_new_row_group; }; +class RowGroupIterationHelper { +public: + RowGroupIterationHelper(RowGroupCollection &collection, DuckTransaction &transaction, + vector column_ids); + +private: + RowGroupCollection &collection; + DuckTransaction &transaction; + vector column_ids; + +private: + class RowGroupIterator { + public: + RowGroupIterator(optional_ptr collection, optional_ptr transaction, + const vector &column_ids); + ~RowGroupIterator(); + //! enable move constructor + RowGroupIterator(RowGroupIterator &&other) noexcept; + + optional_ptr collection; + optional_ptr transaction; + unique_ptr chunk; + unique_ptr state; + + public: + RowGroupIterator &operator++(); + bool operator!=(const RowGroupIterator &other) const; + DataChunk &operator*() const; + }; + +public: + RowGroupIterator begin(); // NOLINT: match stl API + RowGroupIterator end(); // NOLINT: match stl API +}; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table/row_group_reorderer.hpp b/src/duckdb/src/include/duckdb/storage/table/row_group_reorderer.hpp index 4a57a73f6..223d90cb5 100644 --- a/src/duckdb/src/include/duckdb/storage/table/row_group_reorderer.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/row_group_reorderer.hpp @@ -12,15 +12,15 @@ #include "duckdb/storage/table/row_group.hpp" #include "duckdb/storage/table/row_group_segment_tree.hpp" #include "duckdb/storage/table/segment_tree.hpp" +#include "duckdb/common/enums/order_type.hpp" namespace duckdb { -enum class OrderByStatistics { MIN, MAX }; -enum class RowGroupOrderType { ASC, DESC }; -enum class OrderByColumnType { NUMERIC, STRING }; +enum class OrderByStatistics : uint8_t { MIN, MAX }; +enum class OrderByColumnType : uint8_t { NUMERIC, STRING }; struct RowGroupOrderOptions { - RowGroupOrderOptions(const StorageIndex &column_idx_p, OrderByStatistics order_by_p, RowGroupOrderType order_type_p, + RowGroupOrderOptions(const StorageIndex &column_idx_p, OrderByStatistics order_by_p, OrderType order_type_p, OrderByColumnType column_type_p, optional_idx row_limit_p = optional_idx(), idx_t row_group_offset_p = 0) : column_idx(column_idx_p), order_by(order_by_p), order_type(order_type_p), column_type(column_type_p), @@ -29,10 +29,13 @@ struct RowGroupOrderOptions { const StorageIndex column_idx; const OrderByStatistics order_by; - const RowGroupOrderType order_type; + const OrderType order_type; const OrderByColumnType column_type; const optional_idx row_limit; const idx_t row_group_offset; + + void Serialize(Serializer &serializer) const; + static unique_ptr Deserialize(Deserializer &deserializer); }; struct OffsetPruningResult { @@ -48,7 +51,7 @@ class RowGroupReorderer { static Value RetrieveStat(const BaseStatistics &stats, OrderByStatistics order_by, OrderByColumnType column_type); static OffsetPruningResult GetOffsetAfterPruning(OrderByStatistics order_by, OrderByColumnType column_type, - RowGroupOrderType order_type, const StorageIndex &column_idx, + OrderType order_type, const StorageIndex &column_idx, idx_t row_offset, vector &stats); private: diff --git a/src/duckdb/src/include/duckdb/storage/table/row_id_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/row_id_column_data.hpp index 19987764f..c58f2907b 100644 --- a/src/duckdb/src/include/duckdb/storage/table/row_id_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/row_id_column_data.hpp @@ -54,7 +54,8 @@ class RowIdColumnData : public ColumnData { unique_ptr CreateCheckpointState(const RowGroup &row_group, PartialBlockManager &partial_block_manager) override; - unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info) override; + unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &old_stats) override; void CheckpointScan(ColumnSegment &segment, ColumnScanState &state, idx_t count, Vector &scan_vector) const override; diff --git a/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp b/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp index 7d1e92e37..822edc4cb 100644 --- a/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp @@ -132,6 +132,9 @@ struct ColumnScanState { //! Whether or not updates should be allowed UpdateScanType update_scan_type = UpdateScanType::STANDARD; +public: + void PushDownCast(const LogicalType &original_type, const LogicalType &cast_type); + public: void Initialize(const QueryContext &context_p, const LogicalType &type, const StorageIndex &column_id, optional_ptr options); diff --git a/src/duckdb/src/include/duckdb/storage/table/segment_tree.hpp b/src/duckdb/src/include/duckdb/storage/table/segment_tree.hpp index 16d84a80b..4c01fbea1 100644 --- a/src/duckdb/src/include/duckdb/storage/table/segment_tree.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/segment_tree.hpp @@ -243,7 +243,7 @@ class SegmentTree { string error; error = StringUtil::Format("Attempting to find row number \"%lld\" in %lld nodes\n", row_number, nodes.size()); for (idx_t i = 0; i < nodes.size(); i++) { - error += StringUtil::Format("Node %lld: Start %lld, Count %lld", i, nodes[i]->GetRowStart(), + error += StringUtil::Format("* Node %lld: Start %lld, Count %lld\n", i, nodes[i]->GetRowStart(), nodes[i]->GetCount()); } throw InternalException("Could not find node in column segment tree!\n%s", error); diff --git a/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp index b432ba6d4..7249aaf08 100644 --- a/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp @@ -53,7 +53,8 @@ class StandardColumnData : public ColumnData { unique_ptr CreateCheckpointState(const RowGroup &row_group, PartialBlockManager &partial_block_manager) override; - unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info) override; + unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &stats) override; void CheckpointScan(ColumnSegment &segment, ColumnScanState &state, idx_t count, Vector &scan_vector) const override; diff --git a/src/duckdb/src/include/duckdb/storage/table/struct_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/struct_column_data.hpp index a64da2ef3..538152b1d 100644 --- a/src/duckdb/src/include/duckdb/storage/table/struct_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/struct_column_data.hpp @@ -15,6 +15,20 @@ namespace duckdb { //! Struct column data represents a struct class StructColumnData : public ColumnData { +public: + struct StructColumnDataChild { + public: + StructColumnDataChild(ColumnData &col, optional_idx vector_index, ColumnScanState &child, bool should_scan) + : col(col), vector_index(vector_index), state(child), should_scan(should_scan) { + } + + public: + ColumnData &col; + optional_idx vector_index; + ColumnScanState &state; + bool should_scan; + }; + public: StructColumnData(BlockManager &block_manager, DataTableInfo &info, idx_t column_index, LogicalType type, ColumnDataType data_type, optional_ptr parent); @@ -27,8 +41,7 @@ class StructColumnData : public ColumnData { void InitializeScan(ColumnScanState &state) override; void InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) override; - void IterateFields(ColumnScanState &state, - const std::function &callback); + vector GetStructChildren(ColumnScanState &state) const; idx_t Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, idx_t scan_count) override; @@ -53,7 +66,8 @@ class StructColumnData : public ColumnData { unique_ptr CreateCheckpointState(const RowGroup &row_group, PartialBlockManager &partial_block_manager) override; - unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info) override; + unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &old_stats) override; bool IsPersistent() override; bool HasAnyChanges() const override; @@ -67,6 +81,9 @@ class StructColumnData : public ColumnData { void SetValidityData(shared_ptr validity_p); void SetChildData(idx_t i, shared_ptr child_column_p); + const ColumnData &GetChildColumn(idx_t index) const; + + const BaseStatistics &GetChildStats(const ColumnData &child) const override; protected: //! The sub-columns of the struct diff --git a/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp b/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp index 12981b8fe..3e4354d9a 100644 --- a/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp @@ -18,6 +18,8 @@ class ConflictManager; class LocalTableStorage; struct IndexStorageInfo; struct DataTableInfo; +template +class TableIndexIterationHelper; //! IndexBindState to transition index binding phases preventing lock order inversion. enum class IndexBindState : uint8_t { UNBOUND, BINDING, BOUND }; @@ -44,28 +46,25 @@ struct IndexSerializationInfo { transaction_t checkpoint_id; }; +// When serializing indexes, new IndexStorageInfos are created upon BoundIndex serialization, whereas for +// UnboundIndex, IndexStorageInfo already exists inside the UnboundIndex. +// We want to serialize IndexStorageInfo's in the same order that we serialized indexes, which is stored as +// a vector of references in the ordered_infos field here. +// UnboundIndexes still "own" the IndexStorageInfo and so a reference can just be directly pushed. +// For BoundIndexes, however, we need to keep the newly created IndexStorageInfo's alive, and so they +// are stored in this result type. When a BoundIndex is added to bound_infos, a reference to this is then +// pushed to ordered_infos. +struct IndexSerializationResult { + //! The ordered list of references to serialize - preserves iteration order of index_entries + vector> ordered_infos; + //! Storage for bound index infos to keep them alive. + vector bound_infos; +}; + class TableIndexList { public: - //! Scan the index entries, invoking the callback method for every entry. - template - void Scan(T &&callback) { - lock_guard lock(index_entries_lock); - for (auto &entry : index_entries) { - if (callback(*entry->index)) { - break; - } - } - } - - template - void ScanEntries(T &&callback) { - lock_guard lock(index_entries_lock); - for (auto &entry : index_entries) { - if (callback(*entry)) { - break; - } - } - } + TableIndexIterationHelper IndexEntries() const; + TableIndexIterationHelper Indexes() const; //! Adds an index entry to the list of index entries. void AddIndex(unique_ptr index); //! Removes an index entry from the list of index entries. @@ -79,17 +78,16 @@ class TableIndexList { //! Binds unbound indexes possibly present after loading an extension. void Bind(ClientContext &context, DataTableInfo &table_info, const char *index_type = nullptr); //! Returns true, if there are no index entries. - bool Empty() { - lock_guard lock(index_entries_lock); - return index_entries.empty(); + bool Empty() const { + return Count() == 0; } //! Returns the number of index entries. - idx_t Count() { + idx_t Count() const { lock_guard lock(index_entries_lock); return index_entries.size(); } //! Returns true, if there are unbound indexes. - bool HasUnbound() { + bool HasUnbound() const { lock_guard lock(index_entries_lock); return unbound_count != 0; } @@ -99,7 +97,7 @@ class TableIndexList { index_entries = std::move(other.index_entries); } //! Merge any changes added to deltas during a checkpoint back into the main indexes - void MergeCheckpointDeltas(DataTable &storage, transaction_t checkpoint_id); + void MergeCheckpointDeltas(transaction_t checkpoint_id); //! Returns true, if all indexes //! Find the foreign key matching the keys. optional_ptr FindForeignKeyIndex(const vector &fk_keys, const ForeignKeyType fk_type); @@ -109,7 +107,7 @@ class TableIndexList { //! Get the combined column ids of the indexes. unordered_set GetRequiredColumns(); //! Serialize all indexes of the table. - vector SerializeToDisk(QueryContext context, const IndexSerializationInfo &info); + IndexSerializationResult SerializeToDisk(QueryContext context, const IndexSerializationInfo &info); public: //! Initialize an index_chunk from a table. @@ -121,11 +119,48 @@ class TableIndexList { private: //! A lock to prevent any concurrent changes to the index entries. - mutex index_entries_lock; + mutable mutex index_entries_lock; //! The index entries of the table. vector> index_entries; //! Contains the number of unbound indexes. idx_t unbound_count = 0; }; +template +class TableIndexIterationHelper { +public: + TableIndexIterationHelper(mutex &index_lock, const vector> &index_entries); + +private: + unique_lock lock; + const vector> &index_entries; + +private: + class TableIndexIterator { + public: + explicit TableIndexIterator(optional_ptr>> index_entries); + + optional_ptr>> index_entries; + optional_idx index; + + public: + TableIndexIterator &operator++(); + bool operator!=(const TableIndexIterator &other) const; + T &operator*() const; + }; + +public: + TableIndexIterator begin() { // NOLINT: match stl API + return TableIndexIterator(&index_entries); + } + TableIndexIterator end() { // NOLINT: match stl API + return TableIndexIterator(nullptr); + } +}; + +template <> +IndexEntry &TableIndexIterationHelper::TableIndexIterator::operator*() const; +template <> +Index &TableIndexIterationHelper::TableIndexIterator::operator*() const; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table/variant_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/variant_column_data.hpp index 973f8bf72..da3ff73ea 100644 --- a/src/duckdb/src/include/duckdb/storage/table/variant_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/variant_column_data.hpp @@ -15,6 +15,11 @@ namespace duckdb { //! Struct column data represents a struct class VariantColumnData : public ColumnData { +public: + //! Indices into the inner shredded struct: STRUCT(typed_value , untyped_value_index UINTEGER) + static constexpr idx_t TYPED_VALUE_INDEX = 0; + static constexpr idx_t UNTYPED_VALUE_INDEX = 1; + public: VariantColumnData(BlockManager &block_manager, DataTableInfo &info, idx_t column_index, LogicalType type, ColumnDataType data_type, optional_ptr parent); @@ -33,7 +38,6 @@ class VariantColumnData : public ColumnData { void InitializeScan(ColumnScanState &state) override; void InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) override; - Vector CreateUnshreddingIntermediate(idx_t count); idx_t Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, idx_t scan_count) override; idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count, idx_t result_offset = 0) override; @@ -57,7 +61,8 @@ class VariantColumnData : public ColumnData { unique_ptr CreateCheckpointState(const RowGroup &row_group, PartialBlockManager &partial_block_manager) override; - unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info) override; + unique_ptr Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &old_stats) override; bool IsPersistent() override; bool HasAnyChanges() const override; @@ -76,9 +81,14 @@ class VariantColumnData : public ColumnData { void SetChildData(vector> child_data); private: + Vector CreateUnshreddingIntermediate(idx_t count) const; vector> WriteShreddedData(const RowGroup &row_group, const LogicalType &shredded_type, BaseStatistics &stats); + bool PushdownShreddedFieldExtract(const StorageIndex &variant_extract, StorageIndex &out_struct_extract) const; void CreateScanStates(ColumnScanState &state); + idx_t ScanWithCallback(ColumnScanState &state, Vector &result, idx_t target_count, + const std::function &callback) const; LogicalType GetShreddedType(); }; diff --git a/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp b/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp index e9c0bb663..22caabede 100644 --- a/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp +++ b/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp @@ -115,6 +115,8 @@ class WriteAheadLog { //! Truncate the WAL to a previous size, and clear anything currently set in the writer void Truncate(idx_t size); void Flush(); + //! Increment the WAL entry count (for autocheckpoint threshold) + void IncrementWALEntriesCount(); void WriteCheckpoint(MetaBlockPointer meta_block); diff --git a/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp b/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp index 66cac1943..7b029feb5 100644 --- a/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp +++ b/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp @@ -31,7 +31,6 @@ struct DuckCleanupInfo { struct ActiveCheckpointWrapper { explicit ActiveCheckpointWrapper(DuckTransactionManager &manager); - ~ActiveCheckpointWrapper(); void Clear(); @@ -114,7 +113,11 @@ class DuckTransactionManager : public TransactionManager { //! Whether or not we can checkpoint CheckpointDecision CanCheckpoint(DuckTransaction &transaction, unique_ptr &checkpoint_lock, const UndoBufferProperties &properties); + //! Get the checkpoint type of an automatic checkpoint + CheckpointDecision GetCheckpointType(DuckTransaction &transaction, const UndoBufferProperties &undo_properties); + bool HasOtherTransactions(DuckTransaction &transaction); + void CleanupTransactions(); private: //! The current start timestamp used by transactions diff --git a/src/duckdb/src/include/duckdb/transaction/local_storage.hpp b/src/duckdb/src/include/duckdb/transaction/local_storage.hpp index 603bd15c2..2d51384b2 100644 --- a/src/duckdb/src/include/duckdb/transaction/local_storage.hpp +++ b/src/duckdb/src/include/duckdb/transaction/local_storage.hpp @@ -61,8 +61,6 @@ class LocalTableStorage : public enable_shared_from_this { //! The main optimistic data writer associated with this table. OptimisticDataWriter optimistic_writer; - //! Whether or not storage was merged - bool merged_storage = false; //! Whether or not the storage was dropped bool is_dropped = false; @@ -91,6 +89,7 @@ class LocalTableStorage : public enable_shared_from_this { OptimisticDataWriter &GetOptimisticWriter(); RowGroupCollection &GetCollection(); + OptimisticWriteCollection &GetPrimaryCollection(); private: mutex collections_lock; diff --git a/src/duckdb/src/include/duckdb_extension.h b/src/duckdb/src/include/duckdb_extension.h index c023bd8a1..78de2d88a 100644 --- a/src/duckdb/src/include/duckdb_extension.h +++ b/src/duckdb/src/include/duckdb_extension.h @@ -741,6 +741,7 @@ typedef struct { // New string functions that are added #ifdef DUCKDB_EXTENSION_API_VERSION_UNSTABLE char *(*duckdb_value_to_string)(duckdb_value value); + duckdb_error_data (*duckdb_valid_utf8_check)(const char *str, idx_t len); #endif // New functions around the table description @@ -776,7 +777,8 @@ typedef struct { sel_t *(*duckdb_selection_vector_get_data_ptr)(duckdb_selection_vector sel); void (*duckdb_vector_copy_sel)(duckdb_vector src, duckdb_vector dst, duckdb_selection_vector sel, idx_t src_count, idx_t src_offset, idx_t dst_offset); - duckdb_error_data (*duckdb_vector_safe_assign_string_element)(duckdb_vector vector, idx_t index, const char *str); + void (*duckdb_unsafe_vector_assign_string_element_len)(duckdb_vector vector, idx_t index, const char *str, + idx_t str_len); #endif } duckdb_ext_api_v1; @@ -1351,7 +1353,8 @@ typedef struct { #define duckdb_scalar_function_init_get_extra_info duckdb_ext_api.duckdb_scalar_function_init_get_extra_info // Version unstable_new_string_functions -#define duckdb_value_to_string duckdb_ext_api.duckdb_value_to_string +#define duckdb_valid_utf8_check duckdb_ext_api.duckdb_valid_utf8_check +#define duckdb_value_to_string duckdb_ext_api.duckdb_value_to_string // Version unstable_new_table_description_functions #define duckdb_table_description_get_column_count duckdb_ext_api.duckdb_table_description_get_column_count @@ -1367,16 +1370,16 @@ typedef struct { #define duckdb_create_union_value duckdb_ext_api.duckdb_create_union_value // Version unstable_new_vector_functions -#define duckdb_create_vector duckdb_ext_api.duckdb_create_vector -#define duckdb_destroy_vector duckdb_ext_api.duckdb_destroy_vector -#define duckdb_vector_safe_assign_string_element duckdb_ext_api.duckdb_vector_safe_assign_string_element -#define duckdb_slice_vector duckdb_ext_api.duckdb_slice_vector -#define duckdb_vector_copy_sel duckdb_ext_api.duckdb_vector_copy_sel -#define duckdb_vector_reference_value duckdb_ext_api.duckdb_vector_reference_value -#define duckdb_vector_reference_vector duckdb_ext_api.duckdb_vector_reference_vector -#define duckdb_create_selection_vector duckdb_ext_api.duckdb_create_selection_vector -#define duckdb_destroy_selection_vector duckdb_ext_api.duckdb_destroy_selection_vector -#define duckdb_selection_vector_get_data_ptr duckdb_ext_api.duckdb_selection_vector_get_data_ptr +#define duckdb_create_vector duckdb_ext_api.duckdb_create_vector +#define duckdb_destroy_vector duckdb_ext_api.duckdb_destroy_vector +#define duckdb_unsafe_vector_assign_string_element_len duckdb_ext_api.duckdb_unsafe_vector_assign_string_element_len +#define duckdb_slice_vector duckdb_ext_api.duckdb_slice_vector +#define duckdb_vector_copy_sel duckdb_ext_api.duckdb_vector_copy_sel +#define duckdb_vector_reference_value duckdb_ext_api.duckdb_vector_reference_value +#define duckdb_vector_reference_vector duckdb_ext_api.duckdb_vector_reference_vector +#define duckdb_create_selection_vector duckdb_ext_api.duckdb_create_selection_vector +#define duckdb_destroy_selection_vector duckdb_ext_api.duckdb_destroy_selection_vector +#define duckdb_selection_vector_get_data_ptr duckdb_ext_api.duckdb_selection_vector_get_data_ptr //===--------------------------------------------------------------------===// // Struct Global Macros @@ -1416,9 +1419,9 @@ typedef struct { DUCKDB_EXTENSION_EXTERN_C_GUARD_OPEN DUCKDB_CAPI_ENTRY_VISIBILITY DUCKDB_EXTENSION_API bool DUCKDB_EXTENSION_GLUE( \ DUCKDB_EXTENSION_NAME, _init_c_api)(duckdb_extension_info info, struct duckdb_extension_access * access) { \ DUCKDB_EXTENSION_API_INIT(info, access, DUCKDB_EXTENSION_API_VERSION_STRING); \ - duckdb_database db = access->get_database(info); \ + duckdb_database *db = access->get_database(info); \ duckdb_connection conn; \ - if (duckdb_connect(db, &conn) == DuckDBError) { \ + if (duckdb_connect(*db, &conn) == DuckDBError) { \ access->set_error(info, "Failed to open connection to database"); \ return false; \ } \ diff --git a/src/duckdb/src/logging/log_manager.cpp b/src/duckdb/src/logging/log_manager.cpp index 07b31f7af..a8bc5b9ea 100644 --- a/src/duckdb/src/logging/log_manager.cpp +++ b/src/duckdb/src/logging/log_manager.cpp @@ -5,6 +5,7 @@ #include "duckdb/main/database.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/client_data.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/common/local_file_system.hpp" namespace duckdb { @@ -63,7 +64,7 @@ bool LogManager::CanScan(LoggingTargetTable table) { return log_storage->CanScan(table); } -LogManager::LogManager(DatabaseInstance &db, LogConfig config_p) : config(std::move(config_p)) { +LogManager::LogManager(DatabaseInstance &db, LogConfig config_p) : config(std::move(config_p)), db_instance(db) { log_storage = make_uniq(db); } @@ -95,8 +96,12 @@ RegisteredLoggingContext LogManager::RegisterLoggingContextInternal(LoggingConte void LogManager::WriteLogEntry(timestamp_t timestamp, const char *log_type, LogLevel log_level, const char *log_message, const RegisteredLoggingContext &context) { - unique_lock lck(lock); - log_storage->WriteLogEntry(timestamp, log_level, log_type, log_message, context); + if (log_level == LogLevel::LOG_WARNING && Settings::Get(db_instance)) { + throw InvalidInputException(log_message); + } else { + unique_lock lck(lock); + log_storage->WriteLogEntry(timestamp, log_level, log_type, log_message, context); + } } void LogManager::FlushCachedLogEntries(DataChunk &chunk, const RegisteredLoggingContext &context) { diff --git a/src/duckdb/src/logging/logger.cpp b/src/duckdb/src/logging/logger.cpp index 93df24fe5..a6e0facff 100644 --- a/src/duckdb/src/logging/logger.cpp +++ b/src/duckdb/src/logging/logger.cpp @@ -18,6 +18,10 @@ void Logger::WriteLog(const char *log_type, LogLevel log_level, const string_t & WriteLog(log_type, log_level, copied_string.c_str()); } +void Logger::WriteLog(const char *log_type, LogLevel log_level, const char *message) { + WriteLogInternal(log_type, log_level, message); +} + Logger &Logger::Get(const DatabaseInstance &db) { return db.GetLogManager().GlobalLogger(); } @@ -68,7 +72,7 @@ bool ThreadSafeLogger::ShouldLog(const char *log_type, LogLevel log_level) { return true; } -void ThreadSafeLogger::WriteLog(const char *log_type, LogLevel log_level, const char *log_message) { +void ThreadSafeLogger::WriteLogInternal(const char *log_type, LogLevel log_level, const char *log_message) { manager.WriteLogEntry(Timestamp::GetCurrentTimestamp(), log_type, log_level, log_message, context); } @@ -91,8 +95,8 @@ bool ThreadLocalLogger::ShouldLog(const char *log_type, LogLevel log_level) { throw NotImplementedException("ThreadLocalLogger::ShouldLog"); } -void ThreadLocalLogger::WriteLog(const char *log_type, LogLevel log_level, const char *log_message) { - throw NotImplementedException("ThreadLocalLogger::WriteLog"); +void ThreadLocalLogger::WriteLogInternal(const char *log_type, LogLevel log_level, const char *log_message) { + throw NotImplementedException("ThreadLocalLogger::WriteLogInternal"); } void ThreadLocalLogger::Flush() { @@ -120,7 +124,7 @@ void MutableLogger::UpdateConfig(LogConfig &new_config) { mode = config.mode; } -void MutableLogger::WriteLog(const char *log_type, LogLevel log_level, const char *log_message) { +void MutableLogger::WriteLogInternal(const char *log_type, LogLevel log_level, const char *log_message) { manager.WriteLogEntry(Timestamp::GetCurrentTimestamp(), log_type, log_level, log_message, context); } diff --git a/src/duckdb/src/logging/logging.cpp b/src/duckdb/src/logging/logging.cpp index b0a614627..4585c8d7b 100644 --- a/src/duckdb/src/logging/logging.cpp +++ b/src/duckdb/src/logging/logging.cpp @@ -20,17 +20,6 @@ bool LogConfig::IsConsistent() const { return false; } -LogConfig LogConfig::Create(bool enabled, LogLevel level) { - return LogConfig(enabled, level, LogMode::LEVEL_ONLY, nullptr, nullptr); -} -LogConfig LogConfig::CreateFromEnabled(bool enabled, LogLevel level, unordered_set &enabled_log_types) { - return LogConfig(enabled, level, LogMode::ENABLE_SELECTED, enabled_log_types, nullptr); -} - -LogConfig LogConfig::CreateFromDisabled(bool enabled, LogLevel level, unordered_set &disabled_log_types) { - return LogConfig(enabled, level, LogMode::DISABLE_SELECTED, nullptr, disabled_log_types); -} - LogConfig::LogConfig(bool enabled, LogLevel level_p, LogMode mode_p, optional_ptr> enabled_log_types_p, optional_ptr> disabled_log_types_p) diff --git a/src/duckdb/src/main/appender.cpp b/src/duckdb/src/main/appender.cpp index 858011efe..b46e9fff4 100644 --- a/src/duckdb/src/main/appender.cpp +++ b/src/duckdb/src/main/appender.cpp @@ -15,6 +15,16 @@ #include "duckdb/planner/expression_binder/constant_binder.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/execution/expression_executor.hpp" +#include "duckdb/parser/tableref/column_data_ref.hpp" +#include "duckdb/parser/parser.hpp" +#include "duckdb/parser/statement/insert_statement.hpp" +#include "duckdb/parser/statement/delete_statement.hpp" +#include "duckdb/parser/statement/update_statement.hpp" +#include "duckdb/parser/statement/merge_into_statement.hpp" +#include "duckdb/parser/query_node/select_node.hpp" +#include "duckdb/parser/expression/parameter_expression.hpp" +#include "duckdb/parser/tableref/expressionlistref.hpp" +#include "duckdb/planner/binder.hpp" namespace duckdb { @@ -423,6 +433,64 @@ void BaseAppender::ClearColumns() { throw NotImplementedException("ClearColumns is only supported when directly appending to a table"); } +unique_ptr BaseAppender::GetColumnDataTableRef(ColumnDataCollection &collection, const string &table_name, + const vector &expected_names) { + auto column_data_ref = make_uniq(collection); + column_data_ref->alias = table_name.empty() ? "appended_data" : table_name; + ; + column_data_ref->expected_names = expected_names; + return std::move(column_data_ref); +} + +CommonTableExpressionMap &GetCTEMap(SQLStatement &statement) { + switch (statement.type) { + case StatementType::INSERT_STATEMENT: + return statement.Cast().cte_map; + case StatementType::DELETE_STATEMENT: + return statement.Cast().cte_map; + case StatementType::UPDATE_STATEMENT: + return statement.Cast().cte_map; + case StatementType::MERGE_INTO_STATEMENT: + return statement.Cast().cte_map; + default: + throw InvalidInputException( + "Unsupported statement type for appender: expected INSERT, DELETE, UPDATE or MERGE INTO"); + } +} + +unique_ptr BaseAppender::ParseStatement(unique_ptr table_ref, const string &query, + const string &table_name) { + // Parse the query. + Parser parser; + parser.ParseQuery(query); + + // Must be a single statement. + if (parser.statements.size() != 1) { + throw InvalidInputException("Expected exactly one query for appending data."); + } + + // Create the CTE for the appender. + auto cte = make_uniq(); + cte->select_list.push_back(make_uniq()); + cte->from_table = std::move(table_ref); + + // Create the SELECT CTE. + auto cte_select = make_uniq(); + cte_select->node = std::move(cte); + + // Create the CTE info. + auto cte_info = make_uniq(); + cte_info->query = std::move(cte_select); + cte_info->materialized = CTEMaterialize::CTE_MATERIALIZE_NEVER; + + // Add the appender data as a CTE to the CTE map of the statement. + string alias = table_name.empty() ? "appended_data" : table_name; + auto &cte_map = GetCTEMap(*parser.statements[0]); + cte_map.map.insert(alias, std::move(cte_info)); + + return std::move(parser.statements[0]); +} + //===--------------------------------------------------------------------===// // Table Appender //===--------------------------------------------------------------------===// @@ -501,12 +569,53 @@ Appender::~Appender() { Destructor(); } +vector Appender::GetExpectedNames() { + vector expected_names; + for (idx_t i = 0; i < column_ids.size(); i++) { + auto &col_name = description->columns[column_ids[i].index].Name(); + expected_names.push_back(col_name); + } + return expected_names; +} + +string Appender::ConstructQuery(TableDescription &description_p, const string &table_name, + const vector &expected_names) { + string query = "INSERT INTO "; + if (!description_p.database.empty()) { + query += StringUtil::Format("%s.", SQLIdentifier(description_p.database)); + } + if (!description_p.schema.empty()) { + query += StringUtil::Format("%s.", SQLIdentifier(description_p.schema)); + } + query += StringUtil::Format("%s", SQLIdentifier(description_p.table)); + if (!expected_names.empty()) { + query += "("; + for (idx_t i = 0; i < expected_names.size(); i++) { + if (i > 0) { + query += ", "; + } + query += StringUtil::Format("%s", SQLIdentifier(expected_names[i])); + } + query += ")"; + } + query += " FROM "; + query += table_name; + return query; +} + void Appender::FlushInternal(ColumnDataCollection &collection) { auto context_ref = context.lock(); if (!context_ref) { throw InvalidInputException("Appender: Attempting to flush data to a closed connection"); } - context_ref->Append(*description, collection, &column_ids); + + string table_name = "__duckdb_internal_appended_data"; + auto expected_names = GetExpectedNames(); + auto query = ConstructQuery(*description, table_name, expected_names); + + auto table_ref = GetColumnDataTableRef(collection, table_name, expected_names); + auto stmt = ParseStatement(std::move(table_ref), query, table_name); + context_ref->Append(std::move(stmt)); } void Appender::AppendDefault() { @@ -603,9 +712,11 @@ QueryAppender::~QueryAppender() { void QueryAppender::FlushInternal(ColumnDataCollection &collection) { auto context_ref = context.lock(); if (!context_ref) { - throw InvalidInputException("Appender: Attempting to flush data to a closed connection"); + throw InvalidInputException("Attempting to flush query appender data on a closed connection"); } - context_ref->Append(collection, query, names, table_name); + auto table_ref = GetColumnDataTableRef(collection, table_name, names); + auto parsed_statement = ParseStatement(std::move(table_ref), query, table_name); + context_ref->Append(std::move(parsed_statement)); } //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/main/attached_database.cpp b/src/duckdb/src/main/attached_database.cpp index 3a2ce8896..bb6400c38 100644 --- a/src/duckdb/src/main/attached_database.cpp +++ b/src/duckdb/src/main/attached_database.cpp @@ -87,7 +87,7 @@ AttachOptions::AttachOptions(const unordered_map &attach_options, AttachedDatabase::AttachedDatabase(DatabaseInstance &db, AttachedDatabaseType type) : CatalogEntry(CatalogType::DATABASE_ENTRY, type == AttachedDatabaseType::SYSTEM_DATABASE ? SYSTEM_CATALOG : TEMP_CATALOG, 0), - db(db), type(type) { + db(db), type(type), close_lock(make_shared_ptr()) { // This database does not have storage, or uses temporary_objects for in-memory storage. D_ASSERT(type == AttachedDatabaseType::TEMP_DATABASE || type == AttachedDatabaseType::SYSTEM_DATABASE); if (type == AttachedDatabaseType::TEMP_DATABASE) { @@ -104,7 +104,7 @@ AttachedDatabase::AttachedDatabase(DatabaseInstance &db, AttachedDatabaseType ty AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, string name_p, string file_path_p, AttachOptions &options) : CatalogEntry(CatalogType::DATABASE_ENTRY, catalog_p, std::move(name_p)), db(db), parent_catalog(&catalog_p), - attach_options(options.options) { + close_lock(make_shared_ptr()) { if (options.access_mode == AccessMode::READ_ONLY) { type = AttachedDatabaseType::READ_ONLY_DATABASE; } else { @@ -118,13 +118,14 @@ AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, str stored_database_path = std::move(options.stored_database_path); storage = make_uniq(*this, std::move(file_path_p), options); transaction_manager = make_uniq(*this); + attach_options = options.options; internal = true; } AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, StorageExtension &storage_extension_p, ClientContext &context, string name_p, AttachInfo &info, AttachOptions &options) : CatalogEntry(CatalogType::DATABASE_ENTRY, catalog_p, std::move(name_p)), db(db), parent_catalog(&catalog_p), - storage_extension(&storage_extension_p), attach_options(options.options) { + storage_extension(&storage_extension_p), close_lock(make_shared_ptr()) { if (options.access_mode == AccessMode::READ_ONLY) { type = AttachedDatabaseType::READ_ONLY_DATABASE; } else { @@ -148,6 +149,7 @@ AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, Sto throw InternalException( "AttachedDatabase - create_transaction_manager function did not return a transaction manager"); } + attach_options = options.options; internal = true; } @@ -199,11 +201,10 @@ string AttachedDatabase::ExtractDatabaseName(const string &dbpath, FileSystem &f } void AttachedDatabase::InvokeCloseIfLastReference(shared_ptr &attached_db) { - { - lock_guard guard(attached_db->close_lock); - if (attached_db.use_count() == 1) { - attached_db->Close(DatabaseCloseAction::CHECKPOINT); - } + auto close_lock = attached_db->close_lock; + lock_guard guard(*close_lock); + if (attached_db.use_count() == 1) { + attached_db->Close(DatabaseCloseAction::CHECKPOINT); } attached_db.reset(); } diff --git a/src/duckdb/src/main/buffered_data/simple_buffered_data.cpp b/src/duckdb/src/main/buffered_data/simple_buffered_data.cpp index 59cde1f43..175517998 100644 --- a/src/duckdb/src/main/buffered_data/simple_buffered_data.cpp +++ b/src/duckdb/src/main/buffered_data/simple_buffered_data.cpp @@ -55,6 +55,11 @@ StreamExecutionResult SimpleBufferedData::ExecuteTaskInternal(StreamQueryResult if (!cc->IsActiveResult(context_lock, result)) { return StreamExecutionResult::EXECUTION_CANCELLED; } + // Check for interrupt even if the buffer is full. + // Without this check, cancel requests would not be detected until the buffer is drained. + if (cc->interrupted.load(std::memory_order_relaxed)) { + throw InterruptException(); + } if (BufferIsFull()) { // The buffer isn't empty yet, just return return StreamExecutionResult::CHUNK_READY; diff --git a/src/duckdb/src/main/capi/arrow-c.cpp b/src/duckdb/src/main/capi/arrow-c.cpp index f7865bb3f..cf8037e5c 100644 --- a/src/duckdb/src/main/capi/arrow-c.cpp +++ b/src/duckdb/src/main/capi/arrow-c.cpp @@ -79,8 +79,7 @@ duckdb_error_data duckdb_schema_from_arrow(duckdb_connection connection, struct auto arrow_table = duckdb::make_uniq(); try { duckdb::vector return_types; - duckdb::ArrowTableFunction::PopulateArrowTableSchema(duckdb::DBConfig::GetConfig(*conn->context), *arrow_table, - *schema); + duckdb::ArrowTableFunction::PopulateArrowTableSchema(*conn->context, *arrow_table, *schema); } catch (const duckdb::Exception &ex) { return duckdb_create_error_data(DUCKDB_ERROR_INVALID_INPUT, ex.what()); } catch (const std::exception &ex) { diff --git a/src/duckdb/src/main/capi/data_chunk-c.cpp b/src/duckdb/src/main/capi/data_chunk-c.cpp index 9183858ca..67708285e 100644 --- a/src/duckdb/src/main/capi/data_chunk-c.cpp +++ b/src/duckdb/src/main/capi/data_chunk-c.cpp @@ -137,34 +137,40 @@ void duckdb_vector_ensure_validity_writable(duckdb_vector vector) { validity.EnsureWritable(); } -duckdb_error_data duckdb_vector_safe_assign_string_element(duckdb_vector vector, idx_t index, const char *str) { +void duckdb_vector_assign_string_element(duckdb_vector vector, idx_t index, const char *str) { if (!vector) { - return nullptr; + return; + } + auto str_len = strlen(str); + auto error = duckdb_valid_utf8_check(str, str_len); + if (error != nullptr) { + duckdb_destroy_error_data(&error); + duckdb_vector_ensure_validity_writable(vector); + duckdb_validity_set_row_invalid(duckdb_vector_get_validity(vector), index); + return; } + duckdb_unsafe_vector_assign_string_element_len(vector, index, str, str_len); +} +void duckdb_vector_assign_string_element_len(duckdb_vector vector, idx_t index, const char *str, idx_t str_len) { + if (!vector) { + return; + } auto v = reinterpret_cast(vector); - idx_t str_len = strlen(str); - - // UTF-8 analysis for VARCHAR vectors, which expect valid UTF-8. + // UTF-8 validation for VARCHAR vectors. if (v->GetType().id() == duckdb::LogicalTypeId::VARCHAR) { - duckdb::UnicodeInvalidReason reason; - size_t pos; - auto utf_type = duckdb::Utf8Proc::Analyze(str, str_len, &reason, &pos); - if (utf_type == duckdb::UnicodeType::INVALID) { - return duckdb_create_error_data(DUCKDB_ERROR_INVALID_INPUT, - "invalid Unicode detected, str must be valid UTF-8"); + auto error = duckdb_valid_utf8_check(str, str_len); + if (error != nullptr) { + duckdb_destroy_error_data(&error); + duckdb_vector_ensure_validity_writable(vector); + duckdb_validity_set_row_invalid(duckdb_vector_get_validity(vector), index); + return; } } - auto data = duckdb::FlatVector::GetData(*v); - data[index] = duckdb::StringVector::AddStringOrBlob(*v, str, str_len); - return nullptr; + duckdb_unsafe_vector_assign_string_element_len(vector, index, str, str_len); } -void duckdb_vector_assign_string_element(duckdb_vector vector, idx_t index, const char *str) { - duckdb_vector_assign_string_element_len(vector, index, str, strlen(str)); -} - -void duckdb_vector_assign_string_element_len(duckdb_vector vector, idx_t index, const char *str, idx_t str_len) { +void duckdb_unsafe_vector_assign_string_element_len(duckdb_vector vector, idx_t index, const char *str, idx_t str_len) { if (!vector) { return; } diff --git a/src/duckdb/src/main/capi/duckdb_value-c.cpp b/src/duckdb/src/main/capi/duckdb_value-c.cpp index 9c91df242..6e33822eb 100644 --- a/src/duckdb/src/main/capi/duckdb_value-c.cpp +++ b/src/duckdb/src/main/capi/duckdb_value-c.cpp @@ -30,7 +30,11 @@ void duckdb_destroy_value(duckdb_value *value) { } duckdb_value duckdb_create_varchar_length(const char *text, idx_t length) { - return WrapValue(new duckdb::Value(std::string(text, length))); + try { + return WrapValue(new duckdb::Value(std::string(text, length))); + } catch (...) { + return nullptr; + } } duckdb_value duckdb_create_varchar(const char *text) { diff --git a/src/duckdb/src/main/capi/helper-c.cpp b/src/duckdb/src/main/capi/helper-c.cpp index bdf87f2fd..b46fa7fdb 100644 --- a/src/duckdb/src/main/capi/helper-c.cpp +++ b/src/duckdb/src/main/capi/helper-c.cpp @@ -1,4 +1,5 @@ #include "duckdb/main/capi/capi_internal.hpp" +#include "utf8proc_wrapper.hpp" namespace duckdb { @@ -518,3 +519,14 @@ const char *duckdb_string_t_data(duckdb_string_t *string_p) { auto &string = *reinterpret_cast(string_p); return string.GetData(); } + +duckdb_error_data duckdb_valid_utf8_check(const char *str, idx_t len) { + duckdb::UnicodeInvalidReason reason; + size_t pos; + auto utf_type = duckdb::Utf8Proc::Analyze(str, len, &reason, &pos); + if (utf_type == duckdb::UnicodeType::INVALID) { + return duckdb_create_error_data(DUCKDB_ERROR_INVALID_INPUT, + "invalid Unicode detected, str must be valid UTF-8"); + } + return nullptr; +} diff --git a/src/duckdb/src/main/capi/stream-c.cpp b/src/duckdb/src/main/capi/stream-c.cpp index 5b950599f..4dbe58bb4 100644 --- a/src/duckdb/src/main/capi/stream-c.cpp +++ b/src/duckdb/src/main/capi/stream-c.cpp @@ -29,6 +29,9 @@ duckdb_data_chunk duckdb_fetch_chunk(duckdb_result result) { auto chunk = result_instance.Fetch(); return reinterpret_cast(chunk.release()); } catch (std::exception &e) { + // Set the error on the result so duckdb_result_error can retrieve it + duckdb::ErrorData error(e); + result_instance.SetError(error); return nullptr; } } diff --git a/src/duckdb/src/main/client_context.cpp b/src/duckdb/src/main/client_context.cpp index 998cb9772..0c9b1b5d6 100644 --- a/src/duckdb/src/main/client_context.cpp +++ b/src/duckdb/src/main/client_context.cpp @@ -53,6 +53,22 @@ #include "duckdb/main/settings.hpp" #include "duckdb/main/result_set_manager.hpp" +#ifdef __APPLE__ +#include + +// code adapted from Apple's example +// https://developer.apple.com/documentation/apple-silicon/about-the-rosetta-translation-environment#Determine-Whether-Your-App-Is-Running-as-a-Translated-Binary +static bool OsxRosettaIsActive() { + int ret = 0; + size_t size = sizeof(ret); + if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0)) { + return false; + } + return ret == 1; +} + +#endif + namespace duckdb { struct ActiveQueryContext { @@ -155,6 +171,14 @@ ClientContext::ClientContext(shared_ptr database) LoggingContext context(LogContextScope::CONNECTION); logger = db->GetLogManager().CreateLogger(context, true); client_data = make_uniq(*this); + +#ifdef __APPLE__ + if (OsxRosettaIsActive()) { + DUCKDB_LOG_WARNING(*this, "OSX binary translation ('Rosetta') detected. Running DuckDB through Rosetta will " + "cause a significant performance degradation. DuckDB is available natively on Apple " + "silicon, please download an appropriate binary here: https://duckdb.org/install/"); + } +#endif } ClientContext::~ClientContext() { @@ -183,7 +207,7 @@ void ClientContext::Destroy() { void ClientContext::ProcessError(ErrorData &error, const string &query) const { error.FinalizeError(); - if (config.errors_as_json) { + if (Settings::Get(*this)) { error.ConvertErrorToJSON(); } else { error.AddErrorLocation(query); @@ -388,11 +412,23 @@ shared_ptr ClientContext::CreatePreparedStatementInternal result->types = logical_planner.types; result->value_map = std::move(logical_planner.value_map); if (!logical_planner.properties.bound_all_parameters) { + // not all parameters were bound - return return result; } #ifdef DEBUG logical_plan->Verify(*this); #endif + if (result->properties.parameter_count > 0 && !parameters.parameters) { + // if this is a prepared statement we can choose not to fully plan + // if we have parameters, we might want to re-bind when they are available as we can then do more optimizations + // in this situation we check if we want to cache the plan at all + if (!PreparedStatement::CanCachePlan(*logical_plan)) { + // we don't - early-out + result->properties.always_require_rebind = true; + return result; + } + } + if (config.enable_optimizer && logical_plan->RequireOptimizer()) { profiler.StartPhase(MetricType::ALL_OPTIMIZERS); Optimizer optimizer(*logical_planner.binder, *this); @@ -710,8 +746,10 @@ unique_ptr ClientContext::PrepareInternal(ClientContextLock & auto statement_query = statement->query; shared_ptr prepared_data; auto unbound_statement = statement->Copy(); + PendingQueryParameters parameters; RunFunctionInTransactionInternal( - lock, [&]() { prepared_data = CreatePreparedStatement(lock, statement_query, std::move(statement), {}); }, + lock, + [&]() { prepared_data = CreatePreparedStatement(lock, statement_query, std::move(statement), parameters); }, false); prepared_data->unbound_statement = std::move(unbound_statement); return make_uniq(shared_from_this(), std::move(prepared_data), std::move(statement_query), @@ -720,8 +758,10 @@ unique_ptr ClientContext::PrepareInternal(ClientContextLock & unique_ptr ClientContext::Prepare(unique_ptr statement) { auto lock = LockContext(); - // prepare the query + // Store the query in case of an error. auto query = statement->query; + + // Try to prepare. try { InitialCleanup(*lock); return PrepareInternal(*lock, std::move(statement)); @@ -873,6 +913,11 @@ unique_ptr ClientContext::PendingStatementOrPreparedStatemen Parser parser(GetParserOptions()); ErrorData error; parser.ParseQuery(statement->ToString()); + if (statement->type == StatementType::UPDATE_STATEMENT) { + // re-apply `prioritize_table_when_binding` (which is normally set during transform) + parser.statements[0]->Cast().prioritize_table_when_binding = + statement->Cast().prioritize_table_when_binding; + } statement = std::move(parser.statements[0]); } catch (const NotImplementedException &) { // ToString was not implemented, just use the copied statement @@ -1170,6 +1215,7 @@ void ClientContext::RunFunctionInTransactionInternal(ClientContextLock &lock, co if (require_new_transaction) { D_ASSERT(!active_query); transaction.BeginTransaction(); + interrupted = false; } try { fun(); @@ -1225,86 +1271,20 @@ unique_ptr ClientContext::TableInfo(const string &schema_name, return TableInfo(INVALID_CATALOG, schema_name, table_name); } -CommonTableExpressionMap &GetCTEMap(SQLStatement &statement) { - switch (statement.type) { - case StatementType::INSERT_STATEMENT: - return statement.Cast().cte_map; - case StatementType::DELETE_STATEMENT: - return statement.Cast().cte_map; - case StatementType::UPDATE_STATEMENT: - return statement.Cast().cte_map; - case StatementType::MERGE_INTO_STATEMENT: - return statement.Cast().cte_map; - default: - throw InvalidInputException( - "Unsupported statement type for appender: expected INSERT, DELETE, UPDATE or MERGE INTO"); - } -} - -void ClientContext::Append(ColumnDataCollection &collection, const string &query, const vector &column_names, - const string &collection_name) { - // create the CTE for the appender - string alias = collection_name.empty() ? "appended_data" : collection_name; - auto column_data_ref = make_uniq(collection); - column_data_ref->alias = alias; - column_data_ref->expected_names = column_names; - auto cte = make_uniq(); - cte->select_list.push_back(make_uniq()); - cte->from_table = std::move(column_data_ref); - auto cte_select = make_uniq(); - cte_select->node = std::move(cte); - - // parse the query - Parser parser; - parser.ParseQuery(query); - - // must be a single statement with CTEs - if (parser.statements.size() != 1) { - throw InvalidInputException("Expected exactly 1 query for appending data"); - } - - // add the appender data as a CTE to the cte map - auto &cte_map = GetCTEMap(*parser.statements[0]); - auto cte_info = make_uniq(); - cte_info->query = std::move(cte_select); - cte_info->materialized = CTEMaterialize::CTE_MATERIALIZE_NEVER; - - cte_map.map.insert(alias, std::move(cte_info)); - - // now we have the query - run it in a transaction - auto result = Query(std::move(parser.statements[0]), false); +void ClientContext::Append(unique_ptr stmt) { + auto result = Query(std::move(stmt), false); if (result->HasError()) { result->GetErrorObject().Throw("Failed to append: "); } } -void ClientContext::Append(TableDescription &description, ColumnDataCollection &collection, - optional_ptr> column_ids) { +void ClientContext::Append(TableDescription &description, ColumnDataCollection &collection) { string table_name = "__duckdb_internal_appended_data"; - string query = "INSERT INTO "; - if (!description.database.empty()) { - query += StringUtil::Format("%s.", SQLIdentifier(description.database)); - } - if (!description.schema.empty()) { - query += StringUtil::Format("%s.", SQLIdentifier(description.schema)); - } - query += StringUtil::Format("%s", SQLIdentifier(description.table)); - if (column_ids && !column_ids->empty()) { - query += "("; - auto &ids = *column_ids; - for (idx_t i = 0; i < ids.size(); i++) { - if (i > 0) { - query += ", "; - } - auto &col_name = description.columns[ids[i].index].Name(); - query += StringUtil::Format("%s", SQLIdentifier(col_name)); - } - query += ")"; - } - query += " FROM "; - query += table_name; - vector column_names; - Append(collection, query, column_names, table_name); + vector expected_names; + auto query = Appender::ConstructQuery(description, table_name, expected_names); + auto table_ref = BaseAppender::GetColumnDataTableRef(collection, table_name, expected_names); + auto stmt = BaseAppender::ParseStatement(std::move(table_ref), query, table_name); + Append(std::move(stmt)); } void ClientContext::InternalTryBindRelation(Relation &relation, vector &result_columns) { @@ -1424,43 +1404,40 @@ unique_ptr ClientContext::Execute(const shared_ptr &relat return ErrorResult(ErrorData(err_str)); } -SettingLookupResult ClientContext::TryGetCurrentSettingInternal(const string &key, Value &result) const { - // check the client session values - const auto &session_config_map = config.set_variables; - - auto session_value = session_config_map.find(key); - bool found_session_value = session_value != session_config_map.end(); - if (found_session_value) { - result = session_value->second; +SettingLookupResult ClientContext::TryGetCurrentSetting(const string &key, Value &result) const { + optional_ptr option; + // try to get the setting index + auto &db_config = DBConfig::GetConfig(*this); + auto setting_index = db_config.TryGetSettingIndex(key, option); + if (setting_index.IsValid()) { + // generic setting - try to fetch it + auto lookup_result = + config.user_settings.TryGetSetting(db_config.user_settings, setting_index.GetIndex(), result); + if (lookup_result) { + return lookup_result; + } + } + if (option && option->get_setting) { + // legacy callback + result = option->get_setting(*this); return SettingLookupResult(SettingScope::LOCAL); } - // finally check the global session values - return db->TryGetCurrentSetting(key, result); + // setting is not set - get the default value + return DBConfig::TryGetDefaultValue(option, result); } -SettingLookupResult ClientContext::TryGetCurrentSetting(const string &key, Value &result) const { - // first check the built-in settings +SettingLookupResult ClientContext::TryGetCurrentUserSetting(idx_t setting_index, Value &result) const { auto &db_config = DBConfig::GetConfig(*this); - auto option = db_config.GetOptionByName(key); - if (option) { - if (option->get_setting) { - result = option->get_setting(*this); - return SettingLookupResult(SettingScope::LOCAL); - } - // alias - search for the default key - return TryGetCurrentSettingInternal(option->name, result); - } - return TryGetCurrentSettingInternal(key, result); + return config.user_settings.TryGetSetting(db_config.user_settings, setting_index, result); } ParserOptions ClientContext::GetParserOptions() const { - auto &client_config = ClientConfig::GetConfig(*this); ParserOptions options; - options.preserve_identifier_case = DBConfig::GetSetting(*this); - options.integer_division = DBConfig::GetSetting(*this); - options.max_expression_depth = client_config.max_expression_depth; - options.extensions = &DBConfig::GetConfig(*this).parser_extensions; - options.parser_override_setting = DBConfig::GetConfig(*this).options.allow_parser_override_extension; + options.preserve_identifier_case = Settings::Get(*this); + options.integer_division = Settings::Get(*this); + options.max_expression_depth = Settings::Get(*this); + options.extensions = DBConfig::GetConfig(*this).GetCallbackManager(); + options.parser_override_setting = Settings::Get(*this); return options; } @@ -1472,13 +1449,13 @@ ClientProperties ClientContext::GetClientProperties() { timezone = result.ToString(); } ArrowOffsetSize arrow_offset_size = ArrowOffsetSize::REGULAR; - if (DBConfig::GetSetting(*this)) { + if (Settings::Get(*this)) { arrow_offset_size = ArrowOffsetSize::LARGE; } - bool arrow_use_list_view = DBConfig::GetSetting(*this); - bool arrow_lossless_conversion = DBConfig::GetSetting(*this); - bool arrow_use_string_view = DBConfig::GetSetting(*this); - auto arrow_format_version = DBConfig::GetSetting(*this); + bool arrow_use_list_view = Settings::Get(*this); + bool arrow_lossless_conversion = Settings::Get(*this); + bool arrow_use_string_view = Settings::Get(*this); + auto arrow_format_version = Settings::Get(*this); return {timezone, arrow_offset_size, arrow_use_list_view, @@ -1495,4 +1472,12 @@ bool ClientContext::ExecutionIsFinished() { return active_query->executor->ExecutionIsFinished(); } +LogicalType ClientContext::ParseLogicalType(const string &type) { + auto lock = LockContext(); + LogicalType logical_type; + RunFunctionInTransactionInternal(*lock, + [&]() { logical_type = TypeManager::Get(*db).ParseLogicalType(type, *this); }); + return logical_type; +} + } // namespace duckdb diff --git a/src/duckdb/src/main/client_data.cpp b/src/duckdb/src/main/client_data.cpp index ac517736e..6ff938719 100644 --- a/src/duckdb/src/main/client_data.cpp +++ b/src/duckdb/src/main/client_data.cpp @@ -44,7 +44,7 @@ class ClientBufferManager : public BufferManager { auto result = buffer_manager.AllocateTemporaryMemory(tag, block_size, can_destroy); // Track allocation based on actual allocated size from the handle if (result) { - TrackMemoryAllocation(result->GetMemoryUsage()); + TrackMemoryAllocation(result->GetMemory().GetMemoryUsage()); } return result; } @@ -53,7 +53,7 @@ class ClientBufferManager : public BufferManager { auto result = buffer_manager.AllocateMemory(tag, block_manager, can_destroy); // Track allocation based on actual allocated size from the handle if (result) { - TrackMemoryAllocation(result->GetMemoryUsage()); + TrackMemoryAllocation(result->GetMemory().GetMemoryUsage()); } return result; } @@ -61,7 +61,7 @@ class ClientBufferManager : public BufferManager { auto result = buffer_manager.Allocate(tag, block_size, can_destroy); // Track allocation based on actual allocated size from the handle if (result.GetBlockHandle()) { - TrackMemoryAllocation(result.GetBlockHandle()->GetMemoryUsage()); + TrackMemoryAllocation(result.GetBlockHandle()->GetMemory().GetMemoryUsage()); } return result; } @@ -69,19 +69,10 @@ class ClientBufferManager : public BufferManager { auto result = buffer_manager.Allocate(tag, block_manager, can_destroy); // Track allocation based on actual allocated size from the handle if (result.GetBlockHandle()) { - TrackMemoryAllocation(result.GetBlockHandle()->GetMemoryUsage()); + TrackMemoryAllocation(result.GetBlockHandle()->GetMemory().GetMemoryUsage()); } return result; } - void ReAllocate(shared_ptr &handle, idx_t block_size) override { - // Track the difference in size (new size - old size) - idx_t old_size = handle->GetMemoryUsage(); - buffer_manager.ReAllocate(handle, block_size); - idx_t new_size = handle->GetMemoryUsage(); - if (new_size > old_size) { - TrackMemoryAllocation(new_size - old_size); - } - } BufferHandle Pin(shared_ptr &handle) override { return Pin(QueryContext(), handle); } @@ -178,6 +169,9 @@ class ClientBufferManager : public BufferManager { BufferPool &GetBufferPool() const override { return buffer_manager.GetBufferPool(); } + const DatabaseInstance &GetDatabase() const override { + return buffer_manager.GetDatabase(); + } DatabaseInstance &GetDatabase() override { return buffer_manager.GetDatabase(); } @@ -198,8 +192,8 @@ class ClientBufferManager : public BufferManager { unique_ptr buffer) override { return buffer_manager.ReadTemporaryBuffer(context, tag, block, std::move(buffer)); } - void DeleteTemporaryFile(BlockHandle &block) override { - return buffer_manager.DeleteTemporaryFile(block); + void DeleteTemporaryFile(BlockMemory &memory) override { + return buffer_manager.DeleteTemporaryFile(memory); } private: diff --git a/src/duckdb/src/main/config.cpp b/src/duckdb/src/main/config.cpp index b632a4987..c8f9ada59 100644 --- a/src/duckdb/src/main/config.cpp +++ b/src/duckdb/src/main/config.cpp @@ -5,6 +5,7 @@ #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/operator/multiply.hpp" #include "duckdb/common/string_util.hpp" +#include "duckdb/main/database.hpp" #include "duckdb/main/settings.hpp" #include "duckdb/storage/storage_extension.hpp" #include "duckdb/common/serializer/serializer.hpp" @@ -26,30 +27,34 @@ bool DBConfigOptions::debug_print_bindings = false; #define DUCKDB_SETTING(_PARAM) \ { \ _PARAM::Name, _PARAM::Description, _PARAM::InputType, nullptr, nullptr, nullptr, nullptr, nullptr, \ - _PARAM::DefaultScope, _PARAM::DefaultValue, nullptr \ + _PARAM::Scope, _PARAM::DefaultValue, nullptr, _PARAM::SettingIndex \ } #define DUCKDB_SETTING_CALLBACK(_PARAM) \ { \ _PARAM::Name, _PARAM::Description, _PARAM::InputType, nullptr, nullptr, nullptr, nullptr, nullptr, \ - _PARAM::DefaultScope, _PARAM::DefaultValue, _PARAM::OnSet \ + _PARAM::Scope, _PARAM::DefaultValue, _PARAM::OnSet, _PARAM::SettingIndex \ } #define DUCKDB_GLOBAL(_PARAM) \ { \ _PARAM::Name, _PARAM::Description, _PARAM::InputType, _PARAM::SetGlobal, nullptr, _PARAM::ResetGlobal, \ - nullptr, _PARAM::GetSetting, SetScope::AUTOMATIC, nullptr, nullptr \ + nullptr, _PARAM::GetSetting, SettingScopeTarget::INVALID, nullptr, nullptr, optional_idx() \ } #define DUCKDB_LOCAL(_PARAM) \ { \ _PARAM::Name, _PARAM::Description, _PARAM::InputType, nullptr, _PARAM::SetLocal, nullptr, _PARAM::ResetLocal, \ - _PARAM::GetSetting, SetScope::AUTOMATIC, nullptr, nullptr \ + _PARAM::GetSetting, SettingScopeTarget::INVALID, nullptr, nullptr, optional_idx() \ } #define DUCKDB_GLOBAL_LOCAL(_PARAM) \ { \ _PARAM::Name, _PARAM::Description, _PARAM::InputType, _PARAM::SetGlobal, _PARAM::SetLocal, \ - _PARAM::ResetGlobal, _PARAM::ResetLocal, _PARAM::GetSetting, SetScope::AUTOMATIC, nullptr, nullptr \ + _PARAM::ResetGlobal, _PARAM::ResetLocal, _PARAM::GetSetting, SettingScopeTarget::INVALID, nullptr, \ + nullptr, optional_idx() \ } #define FINAL_SETTING \ - { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, SetScope::AUTOMATIC, nullptr, nullptr } + { \ + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, SettingScopeTarget::INVALID, nullptr, \ + nullptr, optional_idx() \ + } #define DUCKDB_SETTING_ALIAS(_ALIAS, _SETTING_INDEX) \ { _ALIAS, _SETTING_INDEX } @@ -59,15 +64,15 @@ bool DBConfigOptions::debug_print_bindings = false; static const ConfigurationOption internal_options[] = { DUCKDB_GLOBAL(AccessModeSetting), - DUCKDB_GLOBAL(AllocatorBackgroundThreadsSetting), + DUCKDB_SETTING_CALLBACK(AllocatorBackgroundThreadsSetting), DUCKDB_GLOBAL(AllocatorBulkDeallocationFlushThresholdSetting), DUCKDB_GLOBAL(AllocatorFlushThresholdSetting), - DUCKDB_GLOBAL(AllowCommunityExtensionsSetting), + DUCKDB_SETTING_CALLBACK(AllowCommunityExtensionsSetting), DUCKDB_SETTING(AllowExtensionsMetadataMismatchSetting), - DUCKDB_GLOBAL(AllowParserOverrideExtensionSetting), + DUCKDB_SETTING_CALLBACK(AllowParserOverrideExtensionSetting), DUCKDB_GLOBAL(AllowPersistentSecretsSetting), - DUCKDB_GLOBAL(AllowUnredactedSecretsSetting), - DUCKDB_GLOBAL(AllowUnsignedExtensionsSetting), + DUCKDB_SETTING_CALLBACK(AllowUnredactedSecretsSetting), + DUCKDB_SETTING_CALLBACK(AllowUnsignedExtensionsSetting), DUCKDB_GLOBAL(AllowedDirectoriesSetting), DUCKDB_GLOBAL(AllowedPathsSetting), DUCKDB_SETTING(ArrowLargeBufferSizeSetting), @@ -75,18 +80,20 @@ static const ConfigurationOption internal_options[] = { DUCKDB_SETTING(ArrowOutputListViewSetting), DUCKDB_SETTING_CALLBACK(ArrowOutputVersionSetting), DUCKDB_SETTING(AsofLoopJoinThresholdSetting), - DUCKDB_GLOBAL(AutoinstallExtensionRepositorySetting), - DUCKDB_GLOBAL(AutoinstallKnownExtensionsSetting), - DUCKDB_GLOBAL(AutoloadKnownExtensionsSetting), + DUCKDB_SETTING(AutoCheckpointSkipWalThresholdSetting), + DUCKDB_SETTING(AutoinstallExtensionRepositorySetting), + DUCKDB_SETTING(AutoinstallKnownExtensionsSetting), + DUCKDB_SETTING(AutoloadKnownExtensionsSetting), DUCKDB_GLOBAL(BlockAllocatorMemorySetting), DUCKDB_SETTING(CatalogErrorMaxSchemasSetting), DUCKDB_GLOBAL(CheckpointThresholdSetting), - DUCKDB_GLOBAL(CustomExtensionRepositorySetting), + DUCKDB_SETTING(CustomExtensionRepositorySetting), DUCKDB_LOCAL(CustomProfilingSettingsSetting), DUCKDB_GLOBAL(CustomUserAgentSetting), DUCKDB_SETTING(DebugAsofIejoinSetting), DUCKDB_SETTING_CALLBACK(DebugCheckpointAbortSetting), DUCKDB_SETTING(DebugCheckpointSleepMsSetting), + DUCKDB_SETTING(DebugEvictionQueueSleepMicroSecondsSetting), DUCKDB_LOCAL(DebugForceExternalSetting), DUCKDB_SETTING(DebugForceNoCrossProductSetting), DUCKDB_SETTING_CALLBACK(DebugPhysicalTableScanExecutionStrategySetting), @@ -94,24 +101,25 @@ static const ConfigurationOption internal_options[] = { DUCKDB_SETTING(DebugVerifyBlocksSetting), DUCKDB_SETTING_CALLBACK(DebugVerifyVectorSetting), DUCKDB_SETTING_CALLBACK(DebugWindowModeSetting), - DUCKDB_GLOBAL(DefaultBlockSizeSetting), + DUCKDB_SETTING_CALLBACK(DefaultBlockSizeSetting), DUCKDB_SETTING_CALLBACK(DefaultCollationSetting), DUCKDB_SETTING_CALLBACK(DefaultNullOrderSetting), DUCKDB_SETTING_CALLBACK(DefaultOrderSetting), DUCKDB_GLOBAL(DefaultSecretStorageSetting), - DUCKDB_GLOBAL(DisableDatabaseInvalidationSetting), + DUCKDB_SETTING_CALLBACK(DeprecatedUsingKeySyntaxSetting), + DUCKDB_SETTING_CALLBACK(DisableDatabaseInvalidationSetting), DUCKDB_SETTING(DisableTimestamptzCastsSetting), DUCKDB_GLOBAL(DisabledCompressionMethodsSetting), DUCKDB_GLOBAL(DisabledFilesystemsSetting), DUCKDB_GLOBAL(DisabledLogTypes), DUCKDB_GLOBAL(DisabledOptimizersSetting), - DUCKDB_GLOBAL(DuckDBAPISetting), + DUCKDB_SETTING_CALLBACK(DuckDBAPISetting), DUCKDB_SETTING(DynamicOrFilterThresholdSetting), - DUCKDB_GLOBAL(EnableExternalAccessSetting), - DUCKDB_GLOBAL(EnableExternalFileCacheSetting), + DUCKDB_SETTING_CALLBACK(EnableExternalAccessSetting), + DUCKDB_SETTING_CALLBACK(EnableExternalFileCacheSetting), DUCKDB_SETTING(EnableFSSTVectorsSetting), DUCKDB_LOCAL(EnableHTTPLoggingSetting), - DUCKDB_GLOBAL(EnableHTTPMetadataCacheSetting), + DUCKDB_SETTING(EnableHTTPMetadataCacheSetting), DUCKDB_GLOBAL(EnableLogging), DUCKDB_SETTING(EnableMacroDependenciesSetting), DUCKDB_SETTING(EnableObjectCacheSetting), @@ -120,34 +128,37 @@ static const ConfigurationOption internal_options[] = { DUCKDB_LOCAL(EnableProgressBarPrintSetting), DUCKDB_SETTING(EnableViewDependenciesSetting), DUCKDB_GLOBAL(EnabledLogTypes), - DUCKDB_LOCAL(ErrorsAsJSONSetting), + DUCKDB_SETTING(ErrorsAsJSONSetting), DUCKDB_SETTING(ExperimentalMetadataReuseSetting), - DUCKDB_LOCAL(ExplainOutputSetting), + DUCKDB_SETTING_CALLBACK(ExplainOutputSetting), DUCKDB_GLOBAL(ExtensionDirectoriesSetting), - DUCKDB_GLOBAL(ExtensionDirectorySetting), - DUCKDB_GLOBAL(ExternalThreadsSetting), - DUCKDB_LOCAL(FileSearchPathSetting), - DUCKDB_GLOBAL(ForceBitpackingModeSetting), - DUCKDB_GLOBAL(ForceCompressionSetting), + DUCKDB_SETTING(ExtensionDirectorySetting), + DUCKDB_SETTING_CALLBACK(ExternalThreadsSetting), + DUCKDB_SETTING(FileSearchPathSetting), + DUCKDB_SETTING_CALLBACK(ForceBitpackingModeSetting), + DUCKDB_SETTING_CALLBACK(ForceCompressionSetting), + DUCKDB_GLOBAL(ForceMbedtlsUnsafeSetting), DUCKDB_GLOBAL(ForceVariantShredding), - DUCKDB_LOCAL(HomeDirectorySetting), + DUCKDB_SETTING(GeometryMinimumShreddingSize), + DUCKDB_SETTING_CALLBACK(HomeDirectorySetting), DUCKDB_LOCAL(HTTPLoggingOutputSetting), - DUCKDB_GLOBAL(HTTPProxySetting), - DUCKDB_GLOBAL(HTTPProxyPasswordSetting), - DUCKDB_GLOBAL(HTTPProxyUsernameSetting), + DUCKDB_SETTING(HTTPProxySetting), + DUCKDB_SETTING(HTTPProxyPasswordSetting), + DUCKDB_SETTING(HTTPProxyUsernameSetting), DUCKDB_SETTING(IeeeFloatingPointOpsSetting), + DUCKDB_SETTING(IgnoreUnknownCrsSetting), DUCKDB_SETTING(ImmediateTransactionModeSetting), DUCKDB_SETTING(IndexScanMaxCountSetting), DUCKDB_SETTING_CALLBACK(IndexScanPercentageSetting), DUCKDB_SETTING(IntegerDivisionSetting), - DUCKDB_LOCAL(LambdaSyntaxSetting), + DUCKDB_SETTING_CALLBACK(LambdaSyntaxSetting), DUCKDB_SETTING(LateMaterializationMaxRowsSetting), - DUCKDB_GLOBAL(LockConfigurationSetting), - DUCKDB_LOCAL(LogQueryPathSetting), + DUCKDB_SETTING(LockConfigurationSetting), + DUCKDB_SETTING_CALLBACK(LogQueryPathSetting), DUCKDB_GLOBAL(LoggingLevel), DUCKDB_GLOBAL(LoggingMode), DUCKDB_GLOBAL(LoggingStorage), - DUCKDB_LOCAL(MaxExpressionDepthSetting), + DUCKDB_SETTING(MaxExpressionDepthSetting), DUCKDB_GLOBAL(MaxMemorySetting), DUCKDB_GLOBAL(MaxTempDirectorySizeSetting), DUCKDB_SETTING(MaxVacuumTasksSetting), @@ -158,9 +169,9 @@ static const ConfigurationOption internal_options[] = { DUCKDB_SETTING_CALLBACK(OrderedAggregateThresholdSetting), DUCKDB_SETTING(PartitionedWriteFlushThresholdSetting), DUCKDB_SETTING(PartitionedWriteMaxOpenFilesSetting), - DUCKDB_GLOBAL(PasswordSetting), + DUCKDB_SETTING(PasswordSetting), DUCKDB_SETTING_CALLBACK(PerfectHtThresholdSetting), - DUCKDB_GLOBAL(PinThreadsSetting), + DUCKDB_SETTING_CALLBACK(PinThreadsSetting), DUCKDB_SETTING(PivotFilterThresholdSetting), DUCKDB_SETTING(PivotLimitSetting), DUCKDB_SETTING(PreferRangeJoinsSetting), @@ -172,7 +183,7 @@ static const ConfigurationOption internal_options[] = { DUCKDB_LOCAL(ProfilingModeSetting), DUCKDB_LOCAL(ProgressBarTimeSetting), DUCKDB_SETTING(ScalarSubqueryErrorOnMultipleRowsSetting), - DUCKDB_GLOBAL(SchedulerProcessPartialSetting), + DUCKDB_SETTING(SchedulerProcessPartialSetting), DUCKDB_LOCAL(SchemaSetting), DUCKDB_LOCAL(SearchPathSetting), DUCKDB_GLOBAL(SecretDirectorySetting), @@ -180,21 +191,23 @@ static const ConfigurationOption internal_options[] = { DUCKDB_GLOBAL(StorageCompatibilityVersionSetting), DUCKDB_LOCAL(StreamingBufferSizeSetting), DUCKDB_GLOBAL(TempDirectorySetting), - DUCKDB_GLOBAL(TempFileEncryptionSetting), + DUCKDB_SETTING_CALLBACK(TempFileEncryptionSetting), DUCKDB_GLOBAL(ThreadsSetting), - DUCKDB_GLOBAL(UsernameSetting), + DUCKDB_SETTING(UsernameSetting), DUCKDB_SETTING_CALLBACK(ValidateExternalFileCacheSetting), - DUCKDB_GLOBAL(VariantMinimumShreddingSize), + DUCKDB_SETTING(VariantMinimumShreddingSizeSetting), + DUCKDB_SETTING(WalAutocheckpointEntriesSetting), + DUCKDB_SETTING_CALLBACK(WarningsAsErrorsSetting), DUCKDB_SETTING(WriteBufferRowGroupCountSetting), - DUCKDB_GLOBAL(ZstdMinStringLengthSetting), + DUCKDB_SETTING(ZstdMinStringLengthSetting), FINAL_SETTING}; -static const ConfigurationAlias setting_aliases[] = {DUCKDB_SETTING_ALIAS("memory_limit", 90), - DUCKDB_SETTING_ALIAS("null_order", 38), - DUCKDB_SETTING_ALIAS("profiling_output", 109), - DUCKDB_SETTING_ALIAS("user", 124), - DUCKDB_SETTING_ALIAS("wal_autocheckpoint", 22), - DUCKDB_SETTING_ALIAS("worker_threads", 123), +static const ConfigurationAlias setting_aliases[] = {DUCKDB_SETTING_ALIAS("memory_limit", 96), + DUCKDB_SETTING_ALIAS("null_order", 40), + DUCKDB_SETTING_ALIAS("profiling_output", 115), + DUCKDB_SETTING_ALIAS("user", 130), + DUCKDB_SETTING_ALIAS("wal_autocheckpoint", 23), + DUCKDB_SETTING_ALIAS("worker_threads", 129), FINAL_ALIAS}; vector DBConfig::GetOptions() { @@ -286,10 +299,10 @@ void DBConfig::SetOptionByName(const string &name, const Value &value) { return; } - auto param = extension_parameters.find(name); - if (param != extension_parameters.end()) { - Value target_value = value.DefaultCastAs(param->second.type); - SetOption(name, std::move(target_value)); + ExtensionOption extension_option; + if (TryGetExtensionOption(name, extension_option)) { + Value target_value = value.DefaultCastAs(extension_option.type); + SetOption(extension_option.setting_index.GetIndex(), std::move(target_value)); } else { options.unrecognized_options[name] = value; } @@ -304,7 +317,6 @@ void DBConfig::SetOptionsByName(const case_insensitive_map_t &values) { } void DBConfig::SetOption(optional_ptr db, const ConfigurationOption &option, const Value &value) { - lock_guard l(config_lock); Value input = value.DefaultCastAs(ParseLogicalType(option.parameter_type)); if (option.default_value) { // generic option @@ -312,52 +324,58 @@ void DBConfig::SetOption(optional_ptr db, const ConfigurationO SettingCallbackInfo info(*this, db); option.set_callback(info, input); } - options.set_variables.emplace(option.name, std::move(input)); + user_settings.SetUserSetting(option.setting_idx.GetIndex(), std::move(input)); return; } if (!option.set_global) { throw InvalidInputException("Could not set option \"%s\" as a global option", option.name); } + lock_guard guard(config_lock); D_ASSERT(option.reset_global); option.set_global(db.get(), *this, input); } void DBConfig::ResetOption(optional_ptr db, const ConfigurationOption &option) { - lock_guard l(config_lock); if (option.default_value) { // generic option - options.set_variables.erase(option.name); + user_settings.ClearSetting(option.setting_idx.GetIndex()); return; } if (!option.reset_global) { throw InternalException("Could not reset option \"%s\" as a global option", option.name); } + lock_guard guard(config_lock); D_ASSERT(option.set_global); option.reset_global(db.get(), *this); } -void DBConfig::SetOption(const String &name, Value value) { - lock_guard l(config_lock); - options.set_variables[name.ToStdString()] = std::move(value); +void DBConfig::SetOption(idx_t setting_index, Value value) { + user_settings.SetUserSetting(setting_index, std::move(value)); +} + +void DBConfig::SetOption(const string &name, Value value) { + optional_ptr option; + auto setting_index = TryGetSettingIndex(name, option); + if (!setting_index.IsValid()) { + throw InternalException("Unrecognized option %s in DBConfig::SetOption", name); + } + SetOption(setting_index.GetIndex(), std::move(value)); } -void DBConfig::ResetOption(const String &name) { - lock_guard l(config_lock); - auto extension_option = extension_parameters.find(name.ToStdString()); - D_ASSERT(extension_option != extension_parameters.end()); - auto &default_value = extension_option->second.default_value; +void DBConfig::ResetOption(const ExtensionOption &extension_option) { + auto &default_value = extension_option.default_value; + auto setting_index = extension_option.setting_index.GetIndex(); if (!default_value.IsNull()) { // Default is not NULL, override the setting - options.set_variables[name.ToStdString()] = default_value; + user_settings.SetUserSetting(setting_index, default_value); } else { // Otherwise just remove it from the 'set_variables' map - options.set_variables.erase(name.ToStdString()); + user_settings.ClearSetting(setting_index); } } -void DBConfig::ResetGenericOption(const String &name) { - lock_guard l(config_lock); - options.set_variables.erase(name.ToStdString()); +void DBConfig::ResetGenericOption(idx_t setting_index) { + user_settings.ClearSetting(setting_index); } LogicalType DBConfig::ParseLogicalType(const string &type) { @@ -370,7 +388,7 @@ LogicalType DBConfig::ParseLogicalType(const string &type) { if (StringUtil::EndsWith(type, "]")) { // array - recurse auto bracket_open_idx = type.rfind('['); - if (bracket_open_idx == DConstants::INVALID_INDEX || bracket_open_idx == 0) { + if (bracket_open_idx == string::npos || bracket_open_idx == 0) { throw InternalException("Ill formatted type: '%s'", type); } idx_t array_size = 0; @@ -442,36 +460,43 @@ LogicalType DBConfig::ParseLogicalType(const string &type) { return LogicalType::STRUCT(struct_members); } - LogicalType type_id = StringUtil::CIEquals(type, "ANY") ? LogicalType::ANY : TransformStringToLogicalTypeId(type); - if (type_id == LogicalTypeId::USER) { + const auto type_id = StringUtil::CIEquals(type, "ANY") ? LogicalTypeId::ANY : TransformStringToLogicalTypeId(type); + if (type_id == LogicalTypeId::UNBOUND) { throw InternalException("Error while generating extension function overloads - unrecognized logical type %s", type); } return type_id; } -bool DBConfig::HasExtensionOption(const string &name) { - lock_guard l(config_lock); - return extension_parameters.find(name) != extension_parameters.end(); +bool DBConfig::HasExtensionOption(const string &name) const { + return user_settings.HasExtensionOption(name); +} + +bool DBConfig::TryGetExtensionOption(const String &name, ExtensionOption &result) const { + return user_settings.TryGetExtensionOption(name, result); } void DBConfig::AddExtensionOption(const string &name, string description, LogicalType parameter, const Value &default_value, set_option_callback_t function, SetScope default_scope) { - lock_guard l(config_lock); - extension_parameters.insert(make_pair( - name, ExtensionOption(std::move(description), std::move(parameter), function, default_value, default_scope))); + ExtensionOption extension_option(std::move(description), std::move(parameter), function, default_value, + default_scope); + auto setting_index = user_settings.AddExtensionOption(name, std::move(extension_option)); // copy over unrecognized options, if they match the new extension option auto iter = options.unrecognized_options.find(name); if (iter != options.unrecognized_options.end()) { - options.set_variables[name] = iter->second; + user_settings.SetUserSetting(setting_index, iter->second); options.unrecognized_options.erase(iter); } - if (!default_value.IsNull() && options.set_variables.find(name) == options.set_variables.end()) { + if (!default_value.IsNull() && !user_settings.IsSet(setting_index)) { // Default value is set, insert it into the 'set_variables' list - options.set_variables[name] = default_value; + user_settings.SetUserSetting(setting_index, default_value); } } +case_insensitive_map_t DBConfig::GetExtensionSettings() const { + return user_settings.GetExtensionSettings(); +} + bool DBConfig::IsInMemoryDatabase(const char *database_path) { if (!database_path) { // Entirely empty @@ -488,7 +513,11 @@ bool DBConfig::IsInMemoryDatabase(const char *database_path) { } CastFunctionSet &DBConfig::GetCastFunctions() { - return *cast_functions; + return type_manager->GetCastFunctions(); +} + +TypeManager &DBConfig::GetTypeManager() { + return *type_manager; } CollationBinding &DBConfig::GetCollationBinding() { @@ -523,7 +552,7 @@ void DBConfig::SetDefaultTempDirectory() { } void DBConfig::CheckLock(const String &name) { - if (!options.lock_configuration) { + if (!Settings::Get(*this)) { // not locked return; } @@ -600,7 +629,7 @@ idx_t DBConfig::ParseMemoryLimit(const string &arg) { if (!error.empty()) { if (error == "Memory cannot be negative") { - result = -1; + result = DConstants::INVALID_INDEX; } else { throw ParserException(error); } @@ -665,44 +694,47 @@ OrderType DBConfig::ResolveOrder(ClientContext &context, OrderType order_type) c if (order_type != OrderType::ORDER_DEFAULT) { return order_type; } - return GetSetting(context); + return Settings::Get(context); } -Value DBConfig::GetSettingInternal(const ClientContext &context, const char *setting, const char *default_value) { - Value result_val; - if (context.TryGetCurrentSetting(setting, result_val)) { - return result_val; - } - return Value(default_value); +SettingLookupResult DBConfig::TryGetCurrentUserSetting(idx_t setting_index, Value &result) const { + return user_settings.TryGetSetting(setting_index, result); } -Value DBConfig::GetSettingInternal(const DBConfig &config, const char *setting, const char *default_value) { - Value result_val; - if (config.TryGetCurrentSetting(setting, result_val)) { - return result_val; +SettingLookupResult DBConfig::TryGetDefaultValue(optional_ptr option, Value &result) { + if (!option || !option->default_value) { + return SettingLookupResult(); } - return Value(default_value); -} - -Value DBConfig::GetSettingInternal(const DatabaseInstance &db, const char *setting, const char *default_value) { - return GetSettingInternal(DBConfig::GetConfig(db), setting, default_value); + auto input_type = ParseLogicalType(option->parameter_type); + result = Value(option->default_value).DefaultCastAs(input_type); + return SettingLookupResult(SettingScope::GLOBAL); } SettingLookupResult DBConfig::TryGetCurrentSetting(const string &key, Value &result) const { - const auto &global_config_map = options.set_variables; + optional_ptr option; + auto setting_index = TryGetSettingIndex(key, option); + if (setting_index.IsValid()) { + auto lookup_result = TryGetCurrentUserSetting(setting_index.GetIndex(), result); + if (lookup_result) { + return lookup_result; + } + } + return TryGetDefaultValue(option, result); +} - auto global_value = global_config_map.find(key); - if (global_value != global_config_map.end()) { - result = global_value->second; - return SettingLookupResult(SettingScope::GLOBAL); +optional_idx DBConfig::TryGetSettingIndex(const String &name, optional_ptr &option) const { + ExtensionOption extension_option; + if (TryGetExtensionOption(name, extension_option)) { + // extension setting + return extension_option.setting_index; } - auto option = GetOptionByName(key); - if (option && option->default_value) { - auto input_type = ParseLogicalType(option->parameter_type); - result = Value(option->default_value).DefaultCastAs(input_type); - return SettingLookupResult(SettingScope::GLOBAL); + option = GetOptionByName(name); + if (option) { + // built-in setting + return option->setting_idx; } - return SettingLookupResult(); + // unknown setting + return optional_idx(); } OrderByNullType DBConfig::ResolveNullOrder(ClientContext &context, OrderType order_type, @@ -710,7 +742,7 @@ OrderByNullType DBConfig::ResolveNullOrder(ClientContext &context, OrderType ord if (null_type != OrderByNullType::ORDER_DEFAULT) { return null_type; } - auto null_order = GetSetting(context); + auto null_order = Settings::Get(context); switch (null_order) { case DefaultOrderByNullType::NULLS_FIRST: return OrderByNullType::NULLS_FIRST; @@ -725,11 +757,16 @@ OrderByNullType DBConfig::ResolveNullOrder(ClientContext &context, OrderType ord } } +string GetDefaultUserAgent() { + return StringUtil::Format("duckdb/%s(%s)", DuckDB::LibraryVersion(), DuckDB::Platform()); +} + const string DBConfig::UserAgent() const { auto user_agent = GetDefaultUserAgent(); - if (!options.duckdb_api.empty()) { - user_agent += " " + options.duckdb_api; + auto duckdb_api = Settings::Get(*this); + if (!duckdb_api.empty()) { + user_agent += " " + duckdb_api; } if (!options.custom_user_agent.empty()) { @@ -738,13 +775,22 @@ const string DBConfig::UserAgent() const { return user_agent; } -string DBConfig::SanitizeAllowedPath(const string &path) const { - auto path_sep = file_system->PathSeparator(path); +ExtensionCallbackManager &DBConfig::GetCallbackManager() { + return *callback_manager; +} + +const ExtensionCallbackManager &DBConfig::GetCallbackManager() const { + return *callback_manager; +} + +string DBConfig::SanitizeAllowedPath(const string &path_p) const { + auto result = file_system->CanonicalizePath(path_p); + // allowed_directories/allowed_path always uses forward slashes regardless of the OS + auto path_sep = file_system->PathSeparator(path_p); if (path_sep != "/") { - // allowed_directories/allowed_path always uses forward slashes regardless of the OS - return StringUtil::Replace(path, path_sep, "/"); + result = StringUtil::Replace(result, path_sep, "/"); } - return path; + return result; } void DBConfig::AddAllowedDirectory(const string &path) { @@ -765,15 +811,17 @@ void DBConfig::AddAllowedPath(const string &path) { } bool DBConfig::CanAccessFile(const string &input_path, FileType type) { - if (options.enable_external_access) { + if (Settings::Get(*this)) { // all external access is allowed return true; } string path = SanitizeAllowedPath(input_path); + if (options.allowed_paths.count(path) > 0) { // path is explicitly allowed return true; } + if (options.allowed_directories.empty()) { // no prefix directories specified return false; @@ -798,27 +846,6 @@ bool DBConfig::CanAccessFile(const string &input_path, FileType type) { return false; } D_ASSERT(StringUtil::EndsWith(prefix, "/")); - // path is inside an allowed directory - HOWEVER, we could still exit the allowed directory using ".." - // we check if we ever exit the allowed directory using ".." by looking at the path fragments - idx_t directory_level = 0; - idx_t current_pos = prefix.size(); - for (; current_pos < path.size(); current_pos++) { - idx_t dir_begin = current_pos; - // find either the end of the path or the directory separator - for (; path[current_pos] != '/' && current_pos < path.size(); current_pos++) { - } - idx_t path_length = current_pos - dir_begin; - if (path_length == 2 && path[dir_begin] == '.' && path[dir_begin + 1] == '.') { - // go up a directory - if (directory_level == 0) { - // we cannot go up past the prefix - return false; - } - --directory_level; - } else if (path_length > 0) { - directory_level++; - } - } return true; } diff --git a/src/duckdb/src/main/connection.cpp b/src/duckdb/src/main/connection.cpp index 5546594a8..586e8755a 100644 --- a/src/duckdb/src/main/connection.cpp +++ b/src/duckdb/src/main/connection.cpp @@ -204,15 +204,6 @@ unique_ptr Connection::ExtractPlan(const string &query) { return context->ExtractPlan(query); } -void Connection::Append(TableDescription &description, DataChunk &chunk) { - if (chunk.size() == 0) { - return; - } - ColumnDataCollection collection(Allocator::Get(*context), chunk.GetTypes()); - collection.Append(chunk); - Append(description, collection); -} - void Connection::Append(TableDescription &description, ColumnDataCollection &collection) { context->Append(description, collection); } diff --git a/src/duckdb/src/main/connection_manager.cpp b/src/duckdb/src/main/connection_manager.cpp index 436c89eff..f97d373aa 100644 --- a/src/duckdb/src/main/connection_manager.cpp +++ b/src/duckdb/src/main/connection_manager.cpp @@ -11,7 +11,7 @@ ConnectionManager::ConnectionManager() : connection_count(0), current_connection void ConnectionManager::AddConnection(ClientContext &context) { lock_guard lock(connections_lock); - for (auto &callback : DBConfig::GetConfig(context).extension_callbacks) { + for (auto &callback : ExtensionCallback::Iterate(context)) { callback->OnConnectionOpened(context); } connections[context] = weak_ptr(context.shared_from_this()); @@ -20,7 +20,7 @@ void ConnectionManager::AddConnection(ClientContext &context) { void ConnectionManager::RemoveConnection(ClientContext &context) { lock_guard lock(connections_lock); - for (auto &callback : DBConfig::GetConfig(context).extension_callbacks) { + for (auto &callback : ExtensionCallback::Iterate(context)) { callback->OnConnectionClosed(context); } connections.erase(context); diff --git a/src/duckdb/src/main/database.cpp b/src/duckdb/src/main/database.cpp index 6badf7f9d..45e28618f 100644 --- a/src/duckdb/src/main/database.cpp +++ b/src/duckdb/src/main/database.cpp @@ -5,6 +5,7 @@ #include "duckdb/execution/index/index_type_set.hpp" #include "duckdb/execution/operator/helper/physical_set.hpp" #include "duckdb/function/cast/cast_function_set.hpp" +#include "duckdb/common/types/type_manager.hpp" #include "duckdb/function/compression_function.hpp" #include "duckdb/main/attached_database.hpp" #include "duckdb/main/client_context.hpp" @@ -34,6 +35,7 @@ #include "mbedtls_wrapper.hpp" #include "duckdb/main/database_file_path_manager.hpp" #include "duckdb/main/result_set_manager.hpp" +#include "duckdb/main/extension_callback_manager.hpp" #ifndef DUCKDB_NO_THREADS #include "duckdb/common/thread.hpp" @@ -47,13 +49,14 @@ DBConfig::DBConfig() { encoding_functions->Initialize(*this); arrow_extensions = make_uniq(); arrow_extensions->Initialize(*this); - cast_functions = make_uniq(*this); + type_manager = make_uniq(*this); collation_bindings = make_uniq(); index_types = make_uniq(); error_manager = make_uniq(); secret_manager = make_uniq(); http_util = make_shared_ptr(); - storage_extensions["__open_file__"] = OpenFileStorageExtension::Create(); + callback_manager = make_uniq(); + callback_manager->Register("__open_file__", OpenFileStorageExtension::Create()); } DBConfig::DBConfig(bool read_only) : DBConfig::DBConfig() { @@ -171,15 +174,15 @@ shared_ptr DatabaseInstance::CreateAttachedDatabase(ClientCont if (!options.db_type.empty()) { // Find the storage extension for this database file. auto extension_name = ExtensionHelper::ApplyExtensionAlias(options.db_type); - auto entry = config.storage_extensions.find(extension_name); - if (entry == config.storage_extensions.end()) { + auto storage_extension = StorageExtension::Find(config, extension_name); + if (!storage_extension) { throw BinderException("Unrecognized storage type \"%s\"", options.db_type); } - if (entry->second->attach != nullptr && entry->second->create_transaction_manager != nullptr) { + if (storage_extension->attach != nullptr && storage_extension->create_transaction_manager != nullptr) { // Use the storage extension to create the initial database. - attached_database = - make_shared_ptr(*this, catalog, *entry->second, context, info.name, info, options); + attached_database = make_shared_ptr(*this, catalog, *storage_extension, context, + info.name, info, options); return attached_database; } @@ -220,7 +223,7 @@ void DatabaseInstance::LoadExtensionSettings() { // copy the map, to protect against modifications during auto unrecognized_options_copy = config.options.unrecognized_options; - if (config.options.autoload_known_extensions) { + if (Settings::Get(*this)) { if (unrecognized_options_copy.empty()) { // Nothing to do return; @@ -243,14 +246,14 @@ void DatabaseInstance::LoadExtensionSettings() { "To set the %s setting, the %s extension needs to be loaded. But it could not be autoloaded.", name, extension_name); } - auto it = config.extension_parameters.find(name); - if (it == config.extension_parameters.end()) { + ExtensionOption extension_option; + if (!config.TryGetExtensionOption(name, extension_option)) { throw InternalException("Extension %s did not provide the '%s' config setting", extension_name, name); } // if the extension provided the option, it should no longer be unrecognized. D_ASSERT(config.options.unrecognized_options.find(name) == config.options.unrecognized_options.end()); auto &context = *con.context; - PhysicalSet::SetExtensionVariable(context, it->second, name, SetScope::GLOBAL, value); + PhysicalSet::SetExtensionVariable(context, extension_option, name, SetScope::GLOBAL, value); extension_options.push_back(name); } @@ -287,11 +290,13 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf log_manager = make_uniq(*this, LogConfig()); log_manager->Initialize(); - external_file_cache = make_uniq(*this, config.options.enable_external_file_cache); + bool enable_external_file_cache = Settings::Get(config); + external_file_cache = make_uniq(*this, enable_external_file_cache); result_set_manager = make_uniq(*this); scheduler = make_uniq(*this); - object_cache = make_uniq(); + object_cache = make_uniq(*config.buffer_pool); + config.buffer_pool->SetObjectCache(object_cache.get()); connection_manager = make_uniq(); extension_manager = make_uniq(*this); @@ -310,8 +315,8 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf if (!config.file_system) { throw InternalException("No file system!?"); } - auto entry = config.storage_extensions.find(config.options.database_type); - if (entry == config.storage_extensions.end()) { + auto storage_extension = StorageExtension::Find(config, config.options.database_type); + if (!storage_extension) { ExtensionHelper::LoadExternalExtension(*this, *config.file_system, config.options.database_type); } } @@ -323,7 +328,7 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf } // only increase thread count after storage init because we get races on catalog otherwise - scheduler->SetThreads(config.options.maximum_threads, config.options.external_threads); + scheduler->SetThreads(config.options.maximum_threads, Settings::Get(config)); scheduler->RelaunchThreads(); } @@ -414,8 +419,9 @@ Allocator &Allocator::Get(AttachedDatabase &db) { void DatabaseInstance::Configure(DBConfig &new_config, const char *database_path) { config.options = new_config.options; + config.user_settings = new_config.user_settings; - if (config.options.duckdb_api.empty()) { + if (Settings::Get(*this).empty()) { config.SetOptionByName("duckdb_api", "cpp"); } @@ -432,13 +438,12 @@ void DatabaseInstance::Configure(DBConfig &new_config, const char *database_path if (config.options.access_mode == AccessMode::UNDEFINED) { config.options.access_mode = AccessMode::READ_WRITE; } - config.extension_parameters = new_config.extension_parameters; if (new_config.file_system) { config.file_system = std::move(new_config.file_system); } else { config.file_system = make_uniq(FileSystem::CreateLocal()); } - if (database_path && !config.options.enable_external_access) { + if (database_path && !Settings::Get(*this)) { config.AddAllowedPath(database_path); config.AddAllowedPath(database_path + string(".wal")); if (!config.options.temporary_directory.empty()) { @@ -448,9 +453,6 @@ void DatabaseInstance::Configure(DBConfig &new_config, const char *database_path if (new_config.secret_manager) { config.secret_manager = std::move(new_config.secret_manager); } - if (!new_config.storage_extensions.empty()) { - config.storage_extensions = std::move(new_config.storage_extensions); - } if (config.options.maximum_memory == DConstants::INVALID_INDEX) { config.SetDefaultMaxMemory(); } @@ -461,11 +463,15 @@ void DatabaseInstance::Configure(DBConfig &new_config, const char *database_path if (!config.allocator) { config.allocator = make_uniq(); } - config.block_allocator = make_uniq(*config.allocator, config.options.default_block_alloc_size, + auto default_block_size = Settings::Get(config); + config.block_allocator = make_uniq(*config.allocator, default_block_size, DBConfig::GetSystemAvailableMemory(*config.file_system) * 8 / 10, config.options.block_allocator_size); config.replacement_scans = std::move(new_config.replacement_scans); - config.parser_extensions = std::move(new_config.parser_extensions); + if (new_config.callback_manager) { + config.callback_manager = std::move(new_config.callback_manager); + new_config.callback_manager = make_uniq(); + } config.error_manager = std::move(new_config.error_manager); if (!config.error_manager) { config.error_manager = make_uniq(); @@ -514,18 +520,44 @@ SettingLookupResult DatabaseInstance::TryGetCurrentSetting(const string &key, Va return db_config.TryGetCurrentSetting(key, result); } -shared_ptr DatabaseInstance::GetEncryptionUtil() { - if (!config.encryption_util || !config.encryption_util->SupportsEncryption()) { +shared_ptr DatabaseInstance::GetMbedTLSUtil(bool force_mbedtls) const { + auto encryption_util = make_shared_ptr(); + + if (force_mbedtls) { + encryption_util->ForceMbedTLSUnsafe(); + } + + return encryption_util; +} + +shared_ptr DatabaseInstance::GetEncryptionUtil(bool read_only) { + auto force_mbedtls = config.options.force_mbedtls; + + if (force_mbedtls) { + // return mbedtls if setting is enabled + return GetMbedTLSUtil(force_mbedtls); + } + + if (!config.encryption_util) { ExtensionHelper::TryAutoLoadExtension(*this, "httpfs"); } if (config.encryption_util) { + // httpfs is correctly loaded return config.encryption_util; } - auto result = make_shared_ptr(); + if (read_only) { + // return mbedtls if database is read only + // and OpenSSL not set + return GetMbedTLSUtil(force_mbedtls); + } - return std::move(result); + throw InvalidConfigurationException( + " DuckDB currently has a read-only crypto module " + "loaded. Please re-open using READONLY, or ensure httpfs is loaded using `LOAD httpfs`. " + " To write an encrypted database that is NOT securely encrypted, one can use SET force_mbedtls_unsafe = " + "'true'."); } ValidChecker &DatabaseInstance::GetValidChecker() { diff --git a/src/duckdb/src/main/database_file_path_manager.cpp b/src/duckdb/src/main/database_file_path_manager.cpp index 2e107210a..3381b4b21 100644 --- a/src/duckdb/src/main/database_file_path_manager.cpp +++ b/src/duckdb/src/main/database_file_path_manager.cpp @@ -2,6 +2,7 @@ #include "duckdb/common/exception/binder_exception.hpp" #include "duckdb/parser/parsed_data/attach_info.hpp" #include "duckdb/main/attached_database.hpp" +#include "duckdb/main/database_manager.hpp" namespace duckdb { @@ -19,9 +20,8 @@ InsertDatabasePathResult DatabaseFilePathManager::InsertDatabasePath(DatabaseMan const string &name, OnCreateConflict on_conflict, AttachOptions &options) { if (path.empty() || path == IN_MEMORY_PATH) { - return InsertDatabasePathResult::SUCCESS; + throw InternalException("DatabaseFilePathManager::InsertDatabasePath - cannot insert in-memory database"); } - lock_guard path_lock(db_paths_lock); auto entry = db_paths.emplace(path, DatabasePathInfo(manager, name, options.access_mode)); if (!entry.second) { diff --git a/src/duckdb/src/main/database_manager.cpp b/src/duckdb/src/main/database_manager.cpp index 80b78ee57..93b323d33 100644 --- a/src/duckdb/src/main/database_manager.cpp +++ b/src/duckdb/src/main/database_manager.cpp @@ -7,15 +7,16 @@ #include "duckdb/main/database.hpp" #include "duckdb/main/database_path_and_type.hpp" #include "duckdb/main/extension_helper.hpp" +#include "duckdb/parser/parsed_data/alter_database_info.hpp" +#include "duckdb/storage/storage_extension.hpp" #include "duckdb/storage/storage_manager.hpp" #include "duckdb/transaction/duck_transaction.hpp" #include "duckdb/transaction/duck_transaction_manager.hpp" -#include "duckdb/parser/parsed_data/alter_database_info.hpp" namespace duckdb { DatabaseManager::DatabaseManager(DatabaseInstance &db) - : next_oid(0), current_query_number(1), current_transaction_id(0) { + : db(db), next_oid(0), current_query_number(1), current_transaction_id(0) { system = make_shared_ptr(db); auto &config = DBConfig::GetConfig(db); path_manager = config.path_manager; @@ -82,6 +83,20 @@ shared_ptr DatabaseManager::GetDatabaseInternal(const lock_gua return entry->second; } +bool RequiresTrackingAttaches(const string &path, const string &db_type) { + // we need to track attaches for file-based duckdb databases + if (!db_type.empty() && !StringUtil::CIEquals(db_type, "duckdb")) { + // not duckdb - don't track + return false; + } + if (path.empty() || path == IN_MEMORY_PATH) { + // in-memory - don't track + return false; + } + // file-based duckdb - track + return true; +} + shared_ptr DatabaseManager::AttachDatabase(ClientContext &context, AttachInfo &info, AttachOptions &options) { string extension = ""; @@ -93,8 +108,42 @@ shared_ptr DatabaseManager::AttachDatabase(ClientContext &cont options.access_mode = AccessMode::READ_ONLY; } } + bool requires_tracking_attaches = RequiresTrackingAttaches(info.path, options.db_type); + if (requires_tracking_attaches) { + // canonicalize the path to the database + auto &fs = FileSystem::GetFileSystem(context); + info.path = fs.CanonicalizePath(info.path); + } + + // for IGNORE / REPLACE ON CONFLICT - first look for an existing entry + if (info.on_conflict == OnCreateConflict::IGNORE_ON_CONFLICT || + info.on_conflict == OnCreateConflict::REPLACE_ON_CONFLICT) { + // constant-time lookup in the catalog for the db name + auto existing_db = GetDatabase(info.name); + if (existing_db) { + if ((existing_db->IsReadOnly() && options.access_mode == AccessMode::READ_WRITE) || + (!existing_db->IsReadOnly() && options.access_mode == AccessMode::READ_ONLY)) { + auto existing_mode = existing_db->IsReadOnly() ? AccessMode::READ_ONLY : AccessMode::READ_WRITE; + auto existing_mode_str = EnumUtil::ToString(existing_mode); + auto attached_mode = EnumUtil::ToString(options.access_mode); + throw BinderException("Database \"%s\" is already attached in %s mode, cannot re-attach in %s mode", + info.name, existing_mode_str, attached_mode); + } + if (!options.default_table.name.empty()) { + existing_db->GetCatalog().SetDefaultTable(options.default_table.schema, options.default_table.name); + } + if (info.on_conflict == OnCreateConflict::REPLACE_ON_CONFLICT) { + // allow custom catalogs to override this behavior + if (!existing_db->GetCatalog().HasConflictingAttachOptions(info.path, options)) { + return existing_db; + } + } else { + return existing_db; + } + } + } - if (options.db_type.empty() || StringUtil::CIEquals(options.db_type, "duckdb")) { + if (requires_tracking_attaches) { // Start timing the ATTACH-delay step. auto profiler = context.client_data->profiler->StartTimer(MetricType::WAITING_TO_ATTACH_LATENCY); @@ -320,7 +369,7 @@ void DatabaseManager::GetDatabaseType(ClientContext &context, AttachInfo &info, } auto extension_name = ExtensionHelper::ApplyExtensionAlias(options.db_type); - if (config.storage_extensions.find(extension_name) != config.storage_extensions.end()) { + if (StorageExtension::Find(config, extension_name)) { // If the database type is already registered, we don't need to load it again. return; } diff --git a/src/duckdb/src/main/db_instance_cache.cpp b/src/duckdb/src/main/db_instance_cache.cpp index a8b87ec06..c774ba86e 100644 --- a/src/duckdb/src/main/db_instance_cache.cpp +++ b/src/duckdb/src/main/db_instance_cache.cpp @@ -26,10 +26,8 @@ static string GetDBAbsolutePath(const string &database_p, FileSystem &fs) { // this database path is handled by a replacement open and is not a file path return database; } - if (fs.IsPathAbsolute(database)) { - return fs.NormalizeAbsolutePath(database); - } - return fs.NormalizeAbsolutePath(fs.JoinPath(FileSystem::GetWorkingDirectory(), database)); + // canonicalize the path + return fs.CanonicalizePath(database); } static string GetCacheKey(const string &database_p, const DBConfig &config) { diff --git a/src/duckdb/src/main/extension/extension_alias.cpp b/src/duckdb/src/main/extension/extension_alias.cpp index 4a1ae7146..9089eb269 100644 --- a/src/duckdb/src/main/extension/extension_alias.cpp +++ b/src/duckdb/src/main/extension/extension_alias.cpp @@ -6,6 +6,7 @@ static const ExtensionAlias internal_aliases[] = {{"http", "httpfs"}, // httpfs {"https", "httpfs"}, {"md", "motherduck"}, // motherduck {"mysql", "mysql_scanner"}, // mysql + {"odbc", "odbc_scanner"}, // odbc {"s3", "httpfs"}, {"postgres", "postgres_scanner"}, // postgres {"sqlite", "sqlite_scanner"}, // sqlite diff --git a/src/duckdb/src/main/extension/extension_helper.cpp b/src/duckdb/src/main/extension/extension_helper.cpp index 9058f19e1..195f53049 100644 --- a/src/duckdb/src/main/extension/extension_helper.cpp +++ b/src/duckdb/src/main/extension/extension_helper.cpp @@ -112,6 +112,7 @@ static const DefaultExtension internal_extensions[] = { {"autocomplete", "Adds support for autocomplete in the shell", DUCKDB_EXTENSION_AUTOCOMPLETE_LINKED}, {"motherduck", "Enables motherduck integration with the system", false}, {"mysql_scanner", "Adds support for connecting to a MySQL database", false}, + {"odbc_scanner", "Adds support for connecting to remote databases over ODBC", false}, {"sqlite_scanner", "Adds support for reading and writing SQLite database files", false}, {"postgres_scanner", "Adds support for connecting to a Postgres database", false}, {"inet", "Adds support for IP-related data types and functions", false}, @@ -143,8 +144,9 @@ DefaultExtension ExtensionHelper::GetDefaultExtension(idx_t index) { // Allow Auto-Install Extensions //===--------------------------------------------------------------------===// static const char *const auto_install[] = { - "motherduck", "postgres_scanner", "mysql_scanner", "sqlite_scanner", "delta", "iceberg", "uc_catalog", - "ui", "ducklake", nullptr}; + "motherduck", "postgres_scanner", "mysql_scanner", "odbc_scanner", "sqlite_scanner", + "delta", "iceberg", "unity_catalog", "ui", "ducklake", + nullptr}; // TODO: unify with new autoload mechanism bool ExtensionHelper::AllowAutoInstall(const string &extension) { @@ -181,18 +183,16 @@ string ExtensionHelper::AddExtensionInstallHintToErrorMsg(DatabaseInstance &db, const string &extension_name) { string install_hint; - auto &config = db.config; - if (!ExtensionHelper::CanAutoloadExtension(extension_name)) { install_hint = "Please try installing and loading the " + extension_name + " extension:\nINSTALL " + extension_name + ";\nLOAD " + extension_name + ";\n\n"; - } else if (!config.options.autoload_known_extensions) { + } else if (!Settings::Get(db)) { install_hint = "Please try installing and loading the " + extension_name + " extension by running:\nINSTALL " + extension_name + ";\nLOAD " + extension_name + ";\n\nAlternatively, consider enabling auto-install " "and auto-load by running:\nSET autoinstall_known_extensions=1;\nSET autoload_known_extensions=1;"; - } else if (!config.options.autoinstall_known_extensions) { + } else if (!Settings::Get(db)) { install_hint = "Please try installing the " + extension_name + " extension by running:\nINSTALL " + extension_name + ";\n\nAlternatively, consider enabling autoinstall by running:\nSET autoinstall_known_extensions=1;"; @@ -209,11 +209,10 @@ bool ExtensionHelper::TryAutoLoadExtension(ClientContext &context, const string if (context.db->ExtensionIsLoaded(extension_name)) { return true; } - auto &dbconfig = DBConfig::GetConfig(context); try { - if (dbconfig.options.autoinstall_known_extensions) { - auto autoinstall_repo = ExtensionRepository::GetRepositoryByUrl( - StringValue::Get(DBConfig::GetConfig(context).options.autoinstall_extension_repo)); + if (Settings::Get(context)) { + auto autoinstall_repo_setting = Settings::Get(context); + auto autoinstall_repo = ExtensionRepository::GetRepositoryByUrl(autoinstall_repo_setting); ExtensionInstallOptions options; options.repository = autoinstall_repo; ExtensionHelper::InstallExtension(context, extension_name, options); @@ -225,10 +224,10 @@ bool ExtensionHelper::TryAutoLoadExtension(ClientContext &context, const string } } -static string GetAutoInstallExtensionsRepository(const DBConfigOptions &options) { - string repository_url = options.autoinstall_extension_repo; +static string GetAutoInstallExtensionsRepository(const DBConfig &config) { + string repository_url = Settings::Get(config); if (repository_url.empty()) { - repository_url = options.custom_extension_repo; + repository_url = Settings::Get(config); } return repository_url; } @@ -240,8 +239,8 @@ bool ExtensionHelper::TryAutoLoadExtension(DatabaseInstance &instance, const str auto &dbconfig = DBConfig::GetConfig(instance); try { auto &fs = FileSystem::GetFileSystem(instance); - if (dbconfig.options.autoinstall_known_extensions) { - auto repository_url = GetAutoInstallExtensionsRepository(dbconfig.options); + if (Settings::Get(instance)) { + auto repository_url = GetAutoInstallExtensionsRepository(dbconfig); auto autoinstall_repo = ExtensionRepository::GetRepositoryByUrl(repository_url); ExtensionInstallOptions options; options.repository = autoinstall_repo; @@ -274,7 +273,7 @@ static ExtensionUpdateResult UpdateExtensionInternal(ClientContext &context, Dat // Parse the version of the extension before updating auto ext_binary_handle = fs.OpenFile(full_extension_path, FileOpenFlags::FILE_FLAGS_READ); auto parsed_metadata = ExtensionHelper::ParseExtensionMetaData(*ext_binary_handle); - if (!parsed_metadata.AppearsValid() && !DBConfig::GetSetting(context)) { + if (!parsed_metadata.AppearsValid() && !Settings::Get(context)) { throw IOException( "Failed to update extension: '%s', the metadata of the extension appears invalid! To resolve this, either " "reinstall the extension using 'FORCE INSTALL %s', manually remove the file '%s', or enable '" @@ -388,8 +387,8 @@ void ExtensionHelper::AutoLoadExtension(DatabaseInstance &db, const string &exte try { auto fs = FileSystem::CreateLocal(); #ifndef DUCKDB_WASM - if (dbconfig.options.autoinstall_known_extensions) { - auto repository_url = GetAutoInstallExtensionsRepository(dbconfig.options); + if (Settings::Get(db)) { + auto repository_url = GetAutoInstallExtensionsRepository(dbconfig); auto autoinstall_repo = ExtensionRepository::GetRepositoryByUrl(repository_url); ExtensionInstallOptions options; options.repository = autoinstall_repo; diff --git a/src/duckdb/src/main/extension/extension_install.cpp b/src/duckdb/src/main/extension/extension_install.cpp index 5241810b0..11b887670 100644 --- a/src/duckdb/src/main/extension/extension_install.cpp +++ b/src/duckdb/src/main/extension/extension_install.cpp @@ -100,8 +100,9 @@ vector ExtensionHelper::GetExtensionDirectoryPath(DatabaseInstance &db, vector extension_directories; auto &config = db.config; - if (!config.options.extension_directory.empty()) { - extension_directories.push_back(config.options.extension_directory); + auto custom_extension_directory = Settings::Get(config); + if (!custom_extension_directory.empty()) { + extension_directories.push_back(custom_extension_directory); } if (!config.options.extension_directories.empty()) { @@ -219,10 +220,25 @@ static unsafe_unique_array ReadExtensionFileFromDisk(FileSystem &fs, con } static void WriteExtensionFileToDisk(QueryContext &query_context, FileSystem &fs, const string &path, void *data, - idx_t data_size) { - auto target_file = fs.OpenFile(path, FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_APPEND | - FileFlags::FILE_FLAGS_FILE_CREATE_NEW); + idx_t data_size, DBConfig &config) { + if (!Settings::Get(config)) { + const bool signature_valid = ExtensionHelper::CheckExtensionBufferSignature( + static_cast(data), data_size, Settings::Get(config)); + if (!signature_valid) { + throw IOException("Attempting to install an extension file that doesn't have a valid signature, see " + "https://duckdb.org/docs/stable/operations_manual/securing_duckdb/securing_extensions"); + } + } + + // Now signature has been checked (if signature checking is enabled) + + // Open target_file, at this points ending with '.duckdb_extension' + auto target_file = + fs.OpenFile(path, FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_READ | FileFlags::FILE_FLAGS_APPEND | + FileFlags::FILE_FLAGS_FILE_CREATE_NEW | FileFlags::FILE_FLAGS_ENABLE_EXTENSION_INSTALL); + // Write content to the file target_file->Write(query_context, data, data_size); + target_file->Close(); target_file.reset(); } @@ -241,7 +257,6 @@ string ExtensionHelper::ExtensionUrlTemplate(optional_ptr(db)) { + if (!metadata_mismatch_error.empty() && !Settings::Get(db)) { throw IOException("Failed to install '%s'\n%s", extension_name, metadata_mismatch_error); } @@ -283,9 +298,23 @@ static void CheckExtensionMetadataOnInstall(DatabaseInstance &db, void *in_buffe // 3. Crash after extension move: extension is now uninstalled, new metadata file present static void WriteExtensionFiles(QueryContext &query_context, FileSystem &fs, const string &temp_path, const string &local_extension_path, void *in_buffer, idx_t file_size, - ExtensionInstallInfo &info) { + ExtensionInstallInfo &info, DBConfig &config) { + // temp_path ends with '.duckdb_extension' + if (!StringUtil::EndsWith(temp_path, ".duckdb_extension")) { + throw InternalException("Extension install temp_path of '%s' is not valid, should end in '.duckdb_extension'", + temp_path); + } + // local_extension_path ends with '.duckdb_extension', and given it will be written only after signature checks, + // it's now loadable + if (!StringUtil::EndsWith(local_extension_path, ".duckdb_extension")) { + throw InternalException("Extension install local_extension_path of '%s' is not valid, should end in " + "'.duckdb_extension'", + temp_path); + } + // Write extension to tmp file - WriteExtensionFileToDisk(query_context, fs, temp_path, in_buffer, file_size); + WriteExtensionFileToDisk(query_context, fs, temp_path, in_buffer, file_size, config); + // When this exit, signature has already being checked (if enabled by config) // Write metadata to tmp file auto metadata_tmp_path = temp_path + ".info"; @@ -310,7 +339,7 @@ static unique_ptr DirectInstallExtension(DatabaseInstance if (context) { auto &db = DatabaseInstance::GetDatabase(*context); if (extension == "httpfs" && !db.ExtensionIsLoaded("httpfs") && - db.config.options.autoload_known_extensions) { + Settings::Get(*context)) { ExtensionHelper::AutoLoadExtension(*context, "httpfs"); } } @@ -369,7 +398,7 @@ static unique_ptr DirectInstallExtension(DatabaseInstance QueryContext query_context(context); WriteExtensionFiles(query_context, fs, temp_path, local_extension_path, extension_decompressed, - extension_decompressed_size, info); + extension_decompressed_size, info, db.config); return make_uniq(info); } @@ -461,7 +490,7 @@ static unique_ptr InstallFromHttpUrl(DatabaseInstance &db, QueryContext query_context(context); auto fs = FileSystem::CreateLocal(); WriteExtensionFiles(query_context, *fs, temp_path, local_extension_path, (void *)decompressed_body.data(), - decompressed_body.size(), info); + decompressed_body.size(), info, db.config); return make_uniq(info); } @@ -476,7 +505,10 @@ static unique_ptr InstallFromRepository(DatabaseInstance & string generated_url = ExtensionHelper::ExtensionFinalizeUrlTemplate(url_template, extension_name); // Special handling for http repository: avoid using regular filesystem (note: the filesystem is not used here) - if (StringUtil::StartsWith(options.repository->path, "http://")) { + if (HTTPUtil::IsHTTPProtocol(options.repository->path)) { + if (db.ExtensionIsLoaded("httpfs")) { + HTTPUtil::BumpToSecureProtocol(generated_url); + } return InstallFromHttpUrl(db, generated_url, extension_name, temp_path, local_extension_path, options, context); } @@ -527,11 +559,12 @@ unique_ptr ExtensionHelper::InstallExtensionInternal(Datab auto extension_name = ApplyExtensionAlias(fs.ExtractBaseName(extension)); string local_extension_path = fs.JoinPath(local_path, extension_name + ".duckdb_extension"); - string temp_path = local_extension_path + ".tmp-" + UUID::ToString(UUID::GenerateRandomUUID()); + string temp_path = + local_extension_path + ".tmp-" + UUID::ToString(UUID::GenerateRandomUUID()) + ".duckdb_extension"; if (fs.FileExists(local_extension_path) && !options.force_install) { // File exists: throw error if origin mismatches - if (options.throw_on_origin_mismatch && !DBConfig::GetSetting(db) && + if (options.throw_on_origin_mismatch && !Settings::Get(db) && fs.FileExists(local_extension_path + ".info")) { ThrowErrorOnMismatchingExtensionOrigin(fs, local_extension_path, extension_name, extension, options.repository); diff --git a/src/duckdb/src/main/extension/extension_load.cpp b/src/duckdb/src/main/extension/extension_load.cpp index 0b88a2071..50f95a2bb 100644 --- a/src/duckdb/src/main/extension/extension_load.cpp +++ b/src/duckdb/src/main/extension/extension_load.cpp @@ -34,6 +34,7 @@ struct DuckDBExtensionLoadState { //! Create a DuckDBExtensionLoadState reference from a C API opaque pointer static DuckDBExtensionLoadState &Get(duckdb_extension_info info) { D_ASSERT(info); + return *reinterpret_cast(info); } @@ -81,14 +82,14 @@ struct ExtensionAccess { } //! Called by the extension get a pointer to the database that is loading it - static duckdb_database GetDatabase(duckdb_extension_info info) { + static duckdb_database *GetDatabase(duckdb_extension_info info) { auto &load_state = DuckDBExtensionLoadState::Get(info); try { // Create the duckdb_database load_state.database_data = make_uniq(); load_state.database_data->database = make_shared_ptr(load_state.db); - return reinterpret_cast(load_state.database_data.get()); + return reinterpret_cast(load_state.database_data.get()); } catch (std::exception &ex) { load_state.has_error = true; load_state.error_data = ErrorData(ex); @@ -164,9 +165,41 @@ static T TryLoadFunctionFromDLL(void *dll, const string &function_name, const st return (T)function; } -static void ComputeSHA256String(const string &to_hash, string *res) { +static void ComputeSHA256Buffer(const char *buffer, const idx_t start, const idx_t end, string *res) { // Invoke MbedTls function to actually compute sha256 - *res = duckdb_mbedtls::MbedTlsWrapper::ComputeSha256Hash(to_hash); + char hash[duckdb_mbedtls::MbedTlsWrapper::SHA256_HASH_LENGTH_BYTES]; + duckdb_mbedtls::MbedTlsWrapper::ComputeSha256Hash(buffer + start, end - start, hash); + *res = std::string(hash, duckdb_mbedtls::MbedTlsWrapper::SHA256_HASH_LENGTH_BYTES); +} + +static void ComputeSHA256String(const string &to_hash, string *res) { + ComputeSHA256Buffer(to_hash.data(), 0, to_hash.length(), res); +} + +static string ComputeFinalHash(const vector &chunks) { + string hash_concatenation; + hash_concatenation.reserve(32 * chunks.size()); // 256 bits -> 32 bytes per chunk + + for (auto &chunk : chunks) { + hash_concatenation += chunk; + } + + string two_level_hash; + ComputeSHA256String(hash_concatenation, &two_level_hash); + + return two_level_hash; +} + +static void IntializeAncillaryData(vector &hash_chunks, vector &splits, idx_t length) { + const idx_t maxLenChunks = 1024ULL * 1024ULL; + const idx_t numChunks = (length + maxLenChunks - 1) / maxLenChunks; + hash_chunks.resize(numChunks); + splits.resize(numChunks + 1); + + for (idx_t i = 0; i < numChunks; i++) { + splits[i] = maxLenChunks * i; + } + splits.back() = length; } static void ComputeSHA256FileSegment(FileHandle *handle, const idx_t start, const idx_t end, string *res) { @@ -189,6 +222,26 @@ static void ComputeSHA256FileSegment(FileHandle *handle, const idx_t start, cons *res = state.Finalize(); } +template +static void ComputeHashesOnSegments(F ComputeHashFun, T handle, const vector &splits, + vector &hash_chunks) { +#ifndef DUCKDB_NO_THREADS + vector threads; + threads.reserve(hash_chunks.size()); + for (idx_t i = 0; i < hash_chunks.size(); i++) { + threads.emplace_back(ComputeHashFun, handle, splits[i], splits[i + 1], &hash_chunks[i]); + } + + for (auto &thread : threads) { + thread.join(); + } +#else + for (idx_t i = 0; i < hash_chunks.size(); i++) { + ComputeHashFun(handle, splits[i], splits[i + 1], &hash_chunks[i]); + } +#endif // DUCKDB_NO_THREADS +} + static string FilterZeroAtEnd(string s) { while (!s.empty() && s.back() == '\0') { s.pop_back(); @@ -257,57 +310,54 @@ ParsedExtensionMetaData ExtensionHelper::ParseExtensionMetaData(FileHandle &hand return ParseExtensionMetaData(metadata_segment.data()); } +static bool CheckKnownSignatures(const string &two_level_hash, const string &signature, + const bool allow_community_extensions) { + for (auto &key : ExtensionHelper::GetPublicKeys(allow_community_extensions)) { + if (duckdb_mbedtls::MbedTlsWrapper::IsValidSha256Signature(key, signature, two_level_hash)) { + return true; + } + } + + return false; +} + bool ExtensionHelper::CheckExtensionSignature(FileHandle &handle, ParsedExtensionMetaData &parsed_metadata, const bool allow_community_extensions) { auto signature_offset = handle.GetFileSize() - ParsedExtensionMetaData::SIGNATURE_SIZE; - const idx_t maxLenChunks = 1024ULL * 1024ULL; - const idx_t numChunks = (signature_offset + maxLenChunks - 1) / maxLenChunks; - vector hash_chunks(numChunks); - vector splits(numChunks + 1); + vector hash_chunks; + vector splits; + IntializeAncillaryData(hash_chunks, splits, signature_offset); - for (idx_t i = 0; i < numChunks; i++) { - splits[i] = maxLenChunks * i; - } - splits.back() = signature_offset; + ComputeHashesOnSegments(ComputeSHA256FileSegment, &handle, splits, hash_chunks); -#ifndef DUCKDB_NO_THREADS - vector threads; - threads.reserve(numChunks); - for (idx_t i = 0; i < numChunks; i++) { - threads.emplace_back(ComputeSHA256FileSegment, &handle, splits[i], splits[i + 1], &hash_chunks[i]); - } + const string resulting_hash = ComputeFinalHash(hash_chunks); - for (auto &thread : threads) { - thread.join(); - } -#else - for (idx_t i = 0; i < numChunks; i++) { - ComputeSHA256FileSegment(&handle, splits[i], splits[i + 1], &hash_chunks[i]); - } -#endif // DUCKDB_NO_THREADS + // TODO maybe we should do a stream read / hash update here + handle.Read((void *)parsed_metadata.signature.data(), parsed_metadata.signature.size(), signature_offset); - string hash_concatenation; - hash_concatenation.reserve(32 * numChunks); // 256 bits -> 32 bytes per chunk + return CheckKnownSignatures(resulting_hash, parsed_metadata.signature, allow_community_extensions); +} - for (auto &hash_chunk : hash_chunks) { - hash_concatenation += hash_chunk; - } +bool ExtensionHelper::CheckExtensionBufferSignature(const char *buffer, idx_t buffer_length, const string &signature, + const bool allow_community_extensions) { + vector hash_chunks; + vector splits; + IntializeAncillaryData(hash_chunks, splits, buffer_length); - string two_level_hash; - ComputeSHA256String(hash_concatenation, &two_level_hash); + ComputeHashesOnSegments(ComputeSHA256Buffer, buffer, splits, hash_chunks); - // TODO maybe we should do a stream read / hash update here - handle.Read((void *)parsed_metadata.signature.data(), parsed_metadata.signature.size(), signature_offset); + const string resulting_hash = ComputeFinalHash(hash_chunks); - for (auto &key : ExtensionHelper::GetPublicKeys(allow_community_extensions)) { - if (duckdb_mbedtls::MbedTlsWrapper::IsValidSha256Signature(key, parsed_metadata.signature, two_level_hash)) { - return true; - break; - } - } + return CheckKnownSignatures(resulting_hash, signature, allow_community_extensions); +} - return false; +bool ExtensionHelper::CheckExtensionBufferSignature(const char *buffer, idx_t total_buffer_length, + const bool allow_community_extensions) { + auto signature_offset = total_buffer_length - ParsedExtensionMetaData::SIGNATURE_SIZE; + string signature = std::string(buffer + signature_offset, ParsedExtensionMetaData::SIGNATURE_SIZE); + + return CheckExtensionBufferSignature(buffer, signature_offset, signature, allow_community_extensions); } bool ExtensionHelper::TryInitialLoad(DatabaseInstance &db, FileSystem &fs, const string &extension, @@ -315,7 +365,7 @@ bool ExtensionHelper::TryInitialLoad(DatabaseInstance &db, FileSystem &fs, const #ifdef DUCKDB_DISABLE_EXTENSION_LOAD throw PermissionException("Loading external extensions is disabled through a compile time flag"); #else - if (!db.config.options.enable_external_access) { + if (!Settings::Get(db)) { throw PermissionException("Loading external extensions is disabled through configuration"); } auto filename = fs.ConvertSeparators(extension); @@ -365,8 +415,9 @@ bool ExtensionHelper::TryInitialLoad(DatabaseInstance &db, FileSystem &fs, const // Collect all directories to search for extensions vector search_directories; - if (!db.config.options.extension_directory.empty()) { - search_directories.push_back(db.config.options.extension_directory); + auto custom_extension_directory = Settings::Get(db); + if (!custom_extension_directory.empty()) { + search_directories.push_back(custom_extension_directory); } if (!db.config.options.extension_directories.empty()) { @@ -402,6 +453,12 @@ bool ExtensionHelper::TryInitialLoad(DatabaseInstance &db, FileSystem &fs, const direct_load = true; filename = fs.ExpandPath(filename); } + if (!StringUtil::EndsWith(filename, ".duckdb_extension")) { + throw PermissionException( + "DuckDB extensions are files ending with '.duckdb_extension', loading different " + "files is not possible, error while loading from '%s', consider 'INSTALL ; LOAD ;'", + filename); + } if (!fs.FileExists(filename)) { string message; bool exact_match = ExtensionHelper::CreateSuggestions(extension, message); @@ -423,11 +480,11 @@ bool ExtensionHelper::TryInitialLoad(DatabaseInstance &db, FileSystem &fs, const metadata_mismatch_error = StringUtil::Format("Failed to load '%s', %s", extension, metadata_mismatch_error); } - if (!db.config.options.allow_unsigned_extensions) { + if (!Settings::Get(db)) { bool signature_valid; if (parsed_metadata.AppearsValid()) { - signature_valid = - CheckExtensionSignature(*handle, parsed_metadata, db.config.options.allow_community_extensions); + bool allow_community_extensions = Settings::Get(db); + signature_valid = CheckExtensionSignature(*handle, parsed_metadata, allow_community_extensions); } else { signature_valid = false; } @@ -439,7 +496,7 @@ bool ExtensionHelper::TryInitialLoad(DatabaseInstance &db, FileSystem &fs, const if (!signature_valid) { throw IOException(db.config.error_manager->FormatException(ErrorType::UNSIGNED_EXTENSION, filename)); } - } else if (!DBConfig::GetSetting(db)) { + } else if (!Settings::Get(db)) { if (!metadata_mismatch_error.empty()) { // Unsigned extensions AND configuration allowing n, loading allowed, mainly for // debugging purposes @@ -514,8 +571,7 @@ ExtensionInitResult ExtensionHelper::InitialLoad(DatabaseInstance &db, FileSyste string error; ExtensionInitResult result; if (!TryInitialLoad(db, fs, extension, result, error)) { - auto &config = DBConfig::GetConfig(db); - if (!config.options.autoinstall_known_extensions || !ExtensionHelper::AllowAutoInstall(extension)) { + if (!Settings::Get(db) || !ExtensionHelper::AllowAutoInstall(extension)) { throw IOException(error); } // the extension load failed - try installing the extension diff --git a/src/duckdb/src/main/extension/extension_loader.cpp b/src/duckdb/src/main/extension/extension_loader.cpp index 8e3433013..20ba800c3 100644 --- a/src/duckdb/src/main/extension/extension_loader.cpp +++ b/src/duckdb/src/main/extension/extension_loader.cpp @@ -148,6 +148,12 @@ void ExtensionLoader::RegisterCollation(CreateCollationInfo &info) { system_catalog.CreateFunction(data, finfo); } +void ExtensionLoader::RegisterCoordinateSystem(CreateCoordinateSystemInfo &info) { + auto &system_catalog = Catalog::GetSystemCatalog(db); + auto data = CatalogTransaction::GetSystemTransaction(db); + system_catalog.CreateCoordinateSystem(data, info); +} + void ExtensionLoader::AddFunctionOverload(ScalarFunction function) { auto &scalar_function = GetFunction(function.name); scalar_function.functions.AddFunction(std::move(function)); diff --git a/src/duckdb/src/main/extension_callback_manager.cpp b/src/duckdb/src/main/extension_callback_manager.cpp new file mode 100644 index 000000000..fc0423d02 --- /dev/null +++ b/src/duckdb/src/main/extension_callback_manager.cpp @@ -0,0 +1,174 @@ +#include "duckdb/main/extension_callback_manager.hpp" +#include "duckdb/parser/parser_extension.hpp" +#include "duckdb/optimizer/optimizer_extension.hpp" +#include "duckdb/planner/operator_extension.hpp" +#include "duckdb/planner/planner_extension.hpp" +#include "duckdb/storage/storage_extension.hpp" +#include "duckdb/planner/extension_callback.hpp" + +namespace duckdb { + +struct ExtensionCallbackRegistry { + //! Extensions made to the parser + vector parser_extensions; + //! Extensions made to the planner + vector planner_extensions; + //! Extensions made to the optimizer + vector optimizer_extensions; + //! Extensions made to binder + vector> operator_extensions; + //! Extensions made to storage + case_insensitive_map_t> storage_extensions; + //! Set of callbacks that can be installed by extensions + vector> extension_callbacks; +}; + +ExtensionCallbackManager &ExtensionCallbackManager::Get(ClientContext &context) { + return DBConfig::GetConfig(context).GetCallbackManager(); +} + +const ExtensionCallbackManager &ExtensionCallbackManager::Get(const ClientContext &context) { + return DBConfig::GetConfig(context).GetCallbackManager(); +} + +ExtensionCallbackManager &ExtensionCallbackManager::Get(DatabaseInstance &db) { + return DBConfig::GetConfig(db).GetCallbackManager(); +} + +ExtensionCallbackManager::ExtensionCallbackManager() : callback_registry(make_shared_ptr()) { +} +ExtensionCallbackManager::~ExtensionCallbackManager() { +} + +void ExtensionCallbackManager::Register(ParserExtension extension) { + lock_guard guard(registry_lock); + auto new_registry = make_shared_ptr(*callback_registry); + new_registry->parser_extensions.push_back(std::move(extension)); + callback_registry.atomic_store(new_registry); +} + +void ExtensionCallbackManager::Register(PlannerExtension extension) { + lock_guard guard(registry_lock); + auto new_registry = make_shared_ptr(*callback_registry); + new_registry->planner_extensions.push_back(std::move(extension)); + callback_registry.atomic_store(new_registry); +} + +void ExtensionCallbackManager::Register(OptimizerExtension extension) { + lock_guard guard(registry_lock); + auto new_registry = make_shared_ptr(*callback_registry); + new_registry->optimizer_extensions.push_back(std::move(extension)); + callback_registry.atomic_store(new_registry); +} + +void ExtensionCallbackManager::Register(shared_ptr extension) { + lock_guard guard(registry_lock); + auto new_registry = make_shared_ptr(*callback_registry); + new_registry->operator_extensions.push_back(std::move(extension)); + callback_registry.atomic_store(new_registry); +} + +void ExtensionCallbackManager::Register(const string &name, shared_ptr extension) { + lock_guard guard(registry_lock); + auto new_registry = make_shared_ptr(*callback_registry); + new_registry->storage_extensions[name] = std::move(extension); + callback_registry.atomic_store(new_registry); +} + +void ExtensionCallbackManager::Register(shared_ptr extension) { + lock_guard guard(registry_lock); + auto new_registry = make_shared_ptr(*callback_registry); + new_registry->extension_callbacks.push_back(std::move(extension)); + callback_registry.atomic_store(new_registry); +} + +template +ExtensionCallbackIteratorHelper::ExtensionCallbackIteratorHelper( + const vector &vec, shared_ptr callback_registry) + : vec(vec), callback_registry(std::move(callback_registry)) { +} + +template +ExtensionCallbackIteratorHelper::~ExtensionCallbackIteratorHelper() { +} + +ExtensionCallbackIteratorHelper> ExtensionCallbackManager::OperatorExtensions() const { + auto registry = callback_registry.atomic_load(); + auto &operator_extensions = registry->operator_extensions; + return ExtensionCallbackIteratorHelper>(operator_extensions, std::move(registry)); +} + +ExtensionCallbackIteratorHelper ExtensionCallbackManager::OptimizerExtensions() const { + auto registry = callback_registry.atomic_load(); + auto &optimizer_extensions = registry->optimizer_extensions; + return ExtensionCallbackIteratorHelper(optimizer_extensions, std::move(registry)); +} + +ExtensionCallbackIteratorHelper ExtensionCallbackManager::ParserExtensions() const { + auto registry = callback_registry.atomic_load(); + auto &parser_extensions = registry->parser_extensions; + return ExtensionCallbackIteratorHelper(parser_extensions, std::move(registry)); +} + +ExtensionCallbackIteratorHelper ExtensionCallbackManager::PlannerExtensions() const { + auto registry = callback_registry.atomic_load(); + auto &planner_extensions = registry->planner_extensions; + return ExtensionCallbackIteratorHelper(planner_extensions, std::move(registry)); +} + +ExtensionCallbackIteratorHelper> ExtensionCallbackManager::ExtensionCallbacks() const { + auto registry = callback_registry.atomic_load(); + auto &extension_callbacks = registry->extension_callbacks; + return ExtensionCallbackIteratorHelper>(extension_callbacks, std::move(registry)); +} + +optional_ptr ExtensionCallbackManager::FindStorageExtension(const string &name) const { + auto registry = callback_registry.atomic_load(); + auto entry = registry->storage_extensions.find(name); + if (entry == registry->storage_extensions.end()) { + return nullptr; + } + return entry->second.get(); +} + +bool ExtensionCallbackManager::HasParserExtensions() const { + auto registry = callback_registry.atomic_load(); + return !registry->parser_extensions.empty(); +} + +void OptimizerExtension::Register(DBConfig &config, OptimizerExtension extension) { + config.GetCallbackManager().Register(std::move(extension)); +} + +void ParserExtension::Register(DBConfig &config, ParserExtension extension) { + config.GetCallbackManager().Register(std::move(extension)); +} + +void PlannerExtension::Register(DBConfig &config, PlannerExtension extension) { + config.GetCallbackManager().Register(std::move(extension)); +} + +void OperatorExtension::Register(DBConfig &config, shared_ptr extension) { + config.GetCallbackManager().Register(std::move(extension)); +} + +optional_ptr StorageExtension::Find(const DBConfig &config, const string &extension_name) { + return config.GetCallbackManager().FindStorageExtension(extension_name); +} + +void ExtensionCallback::Register(DBConfig &config, shared_ptr extension) { + config.GetCallbackManager().Register(std::move(extension)); +} + +void StorageExtension::Register(DBConfig &config, const string &extension_name, + shared_ptr extension) { + config.GetCallbackManager().Register(extension_name, std::move(extension)); +} + +template class ExtensionCallbackIteratorHelper>; +template class ExtensionCallbackIteratorHelper>; +template class ExtensionCallbackIteratorHelper; +template class ExtensionCallbackIteratorHelper; +template class ExtensionCallbackIteratorHelper; + +} // namespace duckdb diff --git a/src/duckdb/src/main/extension_install_info.cpp b/src/duckdb/src/main/extension_install_info.cpp index 8c9e69e00..86cc58be2 100644 --- a/src/duckdb/src/main/extension_install_info.cpp +++ b/src/duckdb/src/main/extension_install_info.cpp @@ -1,6 +1,7 @@ #include "duckdb/main/extension_install_info.hpp" #include "duckdb/common/string.hpp" #include "duckdb/common/file_system.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/common/serializer/buffered_file_reader.hpp" #include "duckdb/common/serializer/binary_deserializer.hpp" @@ -45,8 +46,11 @@ string ExtensionRepository::TryConvertUrlToKnownRepository(const string &url) { } ExtensionRepository ExtensionRepository::GetDefaultRepository(optional_ptr config) { - if (config && !config->options.custom_extension_repo.empty()) { - return ExtensionRepository("", config->options.custom_extension_repo); + if (config) { + auto custom_extension_repo = Settings::Get(*config); + if (!custom_extension_repo.empty()) { + return ExtensionRepository("", custom_extension_repo); + } } return GetCoreRepository(); diff --git a/src/duckdb/src/main/extension_manager.cpp b/src/duckdb/src/main/extension_manager.cpp index fbb2b9cea..24459fabf 100644 --- a/src/duckdb/src/main/extension_manager.cpp +++ b/src/duckdb/src/main/extension_manager.cpp @@ -17,16 +17,14 @@ void ExtensionActiveLoad::FinishLoad(ExtensionInstallInfo &install_info) { info.is_loaded = true; info.install_info = make_uniq(install_info); - auto &callbacks = DBConfig::GetConfig(db).extension_callbacks; - for (auto &callback : callbacks) { + for (auto &callback : ExtensionCallback::Iterate(db)) { callback->OnExtensionLoaded(db, extension_name); } DUCKDB_LOG_INFO(db, extension_name); } void ExtensionActiveLoad::LoadFail(const ErrorData &error) { - auto &callbacks = DBConfig::GetConfig(db).extension_callbacks; - for (auto &callback : callbacks) { + for (auto &callback : ExtensionCallback::Iterate(db)) { callback->OnExtensionLoadFail(db, extension_name, error); } DUCKDB_LOG_INFO(db, "Failed to load extension '%s': %s", extension_name, error.Message()); @@ -104,8 +102,7 @@ unique_ptr ExtensionManager::BeginLoad(const string &name) if (info->is_loaded) { return nullptr; } - auto &callbacks = DBConfig::GetConfig(db).extension_callbacks; - for (auto &callback : callbacks) { + for (auto &callback : ExtensionCallback::Iterate(db)) { callback->OnBeginExtensionLoad(db, extension_name); } // extension is not loaded yet and we are in charge of loading it - return diff --git a/src/duckdb/src/main/http/http_util.cpp b/src/duckdb/src/main/http/http_util.cpp index f562dd8cc..4f73f75df 100644 --- a/src/duckdb/src/main/http/http_util.cpp +++ b/src/duckdb/src/main/http/http_util.cpp @@ -8,6 +8,7 @@ #include "duckdb/main/client_data.hpp" #include "duckdb/main/database.hpp" #include "duckdb/main/database_file_opener.hpp" +#include "duckdb/main/settings.hpp" #ifndef DISABLE_DUCKDB_REMOTE_INSTALL #ifndef DUCKDB_DISABLE_EXTENSION_LOAD @@ -456,16 +457,16 @@ HTTPUtil::RunRequestWithRetry(const std::function(void) void HTTPParams::Initialize(optional_ptr opener) { auto db = FileOpener::TryGetDatabase(opener); if (db) { - auto &config = db->config; - if (!config.options.http_proxy.empty()) { + auto http_proxy_setting = Settings::Get(*db); + if (!http_proxy_setting.empty()) { idx_t port; string host; - HTTPUtil::ParseHTTPProxyHost(config.options.http_proxy, host, port); + HTTPUtil::ParseHTTPProxyHost(http_proxy_setting, host, port); http_proxy = host; http_proxy_port = port; } - http_proxy_username = config.options.http_proxy_username; - http_proxy_password = config.options.http_proxy_password; + http_proxy_username = Settings::Get(*db); + http_proxy_password = Settings::Get(*db); } auto client_context = FileOpener::TryGetClientContext(opener); @@ -515,4 +516,13 @@ unique_ptr HTTPClient::Request(BaseRequest &request) { } } +bool HTTPUtil::IsHTTPProtocol(const string &url) { + return StringUtil::StartsWith(url, "http://"); +} +void HTTPUtil::BumpToSecureProtocol(string &url) { + if (IsHTTPProtocol(url)) { + url = "https://" + url.substr(7); + } +} + } // namespace duckdb diff --git a/src/duckdb/src/main/prepared_statement.cpp b/src/duckdb/src/main/prepared_statement.cpp index 49ff9ac94..b0de40a1c 100644 --- a/src/duckdb/src/main/prepared_statement.cpp +++ b/src/duckdb/src/main/prepared_statement.cpp @@ -70,19 +70,34 @@ case_insensitive_map_t PreparedStatement::GetExpectedParameterTypes unique_ptr PreparedStatement::Execute(case_insensitive_map_t &named_values, bool allow_stream_result) { - auto pending = PendingQuery(named_values, allow_stream_result); - if (pending->HasError()) { - return make_uniq(pending->GetErrorObject()); + if (!success) { + return make_uniq( + ErrorData(InvalidInputException("Attempting to execute an unsuccessfully prepared statement!"))); + } + + try { + VerifyParameters(named_values, named_param_map); + } catch (const std::exception &ex) { + return make_uniq(ErrorData(ex)); } - return pending->Execute(); + + PendingQueryParameters parameters; + parameters.parameters = &named_values; + D_ASSERT(data); + parameters.query_parameters.output_type = + allow_stream_result && data->properties.output_type == QueryResultOutputType::ALLOW_STREAMING + ? QueryResultOutputType::ALLOW_STREAMING + : QueryResultOutputType::FORCE_MATERIALIZED; + + return context->Execute(query, data, parameters); } unique_ptr PreparedStatement::Execute(vector &values, bool allow_stream_result) { - auto pending = PendingQuery(values, allow_stream_result); - if (pending->HasError()) { - return make_uniq(pending->GetErrorObject()); + case_insensitive_map_t named_values; + for (idx_t i = 0; i < values.size(); i++) { + named_values[std::to_string(i + 1)] = BoundParameterData(values[i]); } - return pending->Execute(); + return Execute(named_values, allow_stream_result); } unique_ptr PreparedStatement::PendingQuery(vector &values, bool allow_stream_result) { @@ -119,4 +134,25 @@ unique_ptr PreparedStatement::PendingQuery(case_insensitive_ return result; } +bool PreparedStatement::CanCachePlan(const LogicalOperator &root) { + vector> operators; + operators.push_back(root); + + for (idx_t i = 0; i < operators.size(); i++) { + auto &op = operators[i].get(); + switch (op.type) { + case LogicalOperatorType::LOGICAL_GET: + // this operator prevents caching + return false; + default: + break; + } + // investigate the children of this operator + for (auto &child : op.children) { + operators.push_back(*child); + } + } + return true; +} + } // namespace duckdb diff --git a/src/duckdb/src/main/query_profiler.cpp b/src/duckdb/src/main/query_profiler.cpp index 17e5f1f42..b7ce968be 100644 --- a/src/duckdb/src/main/query_profiler.cpp +++ b/src/duckdb/src/main/query_profiler.cpp @@ -25,7 +25,8 @@ using namespace duckdb_yyjson; // NOLINT namespace duckdb { QueryProfiler::QueryProfiler(ClientContext &context_p) - : context(context_p), running(false), query_requires_profiling(false), is_explain_analyze(false) { + : context(context_p), running(false), query_requires_profiling(false), is_explain_analyze(false), + metrics_finalized(false) { } bool QueryProfiler::IsEnabled() const { @@ -107,6 +108,7 @@ void QueryProfiler::Reset() { phase_stack.clear(); running = false; query_metrics.Reset(); + metrics_finalized = false; } void QueryProfiler::StartQuery(const string &query, bool is_explain_analyze_p, bool start_at_optimizer) { @@ -199,39 +201,14 @@ void QueryProfiler::EndQuery() { return; } - query_metrics.latency_timer->EndTimer(); - if (root) { - auto &info = root->GetProfilingInfo(); - if (info.Enabled(info.expanded_settings, MetricType::OPERATOR_CARDINALITY)) { - Finalize(*root->GetChild(0)); - } - } + FinalizeMetricsInternal(); running = false; bool emit_output = false; // Print or output the query profiling after query termination. // EXPLAIN ANALYZE output is not written by the profiler. - if (IsEnabled() && !is_explain_analyze) { - if (root) { - auto &info = root->GetProfilingInfo(); - auto &child_info = root->children[0]->GetProfilingInfo(); - - const auto &settings = info.expanded_settings; - for (const auto &global_info_entry : query_metrics.query_global_info.metrics) { - info.metrics[global_info_entry.first] = global_info_entry.second; - } - - MoveOptimizerPhasesToRoot(); - for (auto &metric : info.metrics) { - if (info.Enabled(settings, metric.first)) { - ProfilingUtils::CollectMetrics(metric.first, query_metrics, metric.second, *root, child_info); - } - } - } - - if (ClientConfig::GetConfig(context).emit_profiler_output) { - emit_output = true; - } + if (IsEnabled() && !is_explain_analyze && ClientConfig::GetConfig(context).emit_profiler_output) { + emit_output = true; } is_explain_analyze = false; @@ -254,6 +231,11 @@ void QueryProfiler::EndQuery() { } } +void QueryProfiler::FinalizeMetrics() { + lock_guard guard(lock); + FinalizeMetricsInternal(); +} + void QueryProfiler::AddToCounter(const MetricType type, const idx_t amount) { if (IsEnabled()) { query_metrics.UpdateMetric(type, amount); @@ -443,9 +425,19 @@ void OperatorProfiler::FinishSource(GlobalSourceState &gstate, LocalSourceState active_operator.get()->type == PhysicalOperatorType::TABLE_SCAN) { const auto &table_scan = active_operator->Cast(); const auto rows_scanned = table_scan.GetRowsScanned(gstate, lstate); + auto &info = GetOperatorInfo(*active_operator); if (rows_scanned.IsValid()) { - auto &info = GetOperatorInfo(*active_operator); + // Use exact value if available. info.AddMetric(MetricType::OPERATOR_ROWS_SCANNED, rows_scanned.GetIndex()); + } else { + // Otherwise estimate as the cardinality of the table scan, if there is no exact value available. + auto &bind_data = table_scan.bind_data; + if (bind_data && table_scan.function.cardinality) { + auto cardinality = table_scan.function.cardinality(context, &(*bind_data)); + if (cardinality && cardinality->has_estimated_cardinality) { + info.AddMetric(MetricType::OPERATOR_ROWS_SCANNED, cardinality->estimated_cardinality); + } + } } } } @@ -801,13 +793,11 @@ string QueryProfiler::ToJSON() const { } void QueryProfiler::WriteToFile(const char *path, string &info) const { - ofstream out(path); - out << info; - out.close(); - // throw an IO exception if it fails to write the file - if (out.fail()) { - throw IOException(strerror(errno)); - } + auto &fs = FileSystem::GetFileSystem(context); + auto flags = FileOpenFlags::FILE_FLAGS_WRITE | FileOpenFlags::FILE_FLAGS_FILE_CREATE_NEW; + auto file = fs.OpenFile(path, flags); + file->Write((void *)info.c_str(), info.size()); + file->Close(); } profiler_settings_t EraseQueryRootSettings(profiler_settings_t settings) { @@ -945,4 +935,33 @@ void QueryProfiler::MoveOptimizerPhasesToRoot() { } } +void QueryProfiler::FinalizeMetricsInternal() { + if (metrics_finalized || !IsEnabled() || !root) { + return; + } + + if (query_metrics.latency_timer) { + query_metrics.latency_timer->EndTimer(); + } + + auto &info = root->GetProfilingInfo(); + if (info.Enabled(info.expanded_settings, MetricType::OPERATOR_CARDINALITY)) { + Finalize(*root->GetChild(0)); + } + + auto &child_info = root->children[0]->GetProfilingInfo(); + const auto &settings = info.expanded_settings; + for (const auto &global_info_entry : query_metrics.query_global_info.metrics) { + info.metrics[global_info_entry.first] = global_info_entry.second; + } + + MoveOptimizerPhasesToRoot(); + for (auto &metric : info.metrics) { + if (info.Enabled(settings, metric.first)) { + ProfilingUtils::CollectMetrics(metric.first, query_metrics, metric.second, *root, child_info); + } + } + metrics_finalized = true; +} + } // namespace duckdb diff --git a/src/duckdb/src/main/secret/default_secrets.cpp b/src/duckdb/src/main/secret/default_secrets.cpp index 2dd9fbc85..631c1abe7 100644 --- a/src/duckdb/src/main/secret/default_secrets.cpp +++ b/src/duckdb/src/main/secret/default_secrets.cpp @@ -26,6 +26,7 @@ vector CreateHTTPSecretFunctions::GetDefaultSecretFunction http_config_fun.provider = "config"; http_config_fun.function = CreateHTTPSecretFromConfig; + http_config_fun.named_parameters["verify_ssl"] = LogicalType::BOOLEAN; http_config_fun.named_parameters["http_proxy"] = LogicalType::VARCHAR; http_config_fun.named_parameters["http_proxy_password"] = LogicalType::VARCHAR; http_config_fun.named_parameters["http_proxy_username"] = LogicalType::VARCHAR; @@ -41,6 +42,7 @@ vector CreateHTTPSecretFunctions::GetDefaultSecretFunction http_env_fun.provider = "env"; http_env_fun.function = CreateHTTPSecretFromEnv; + http_env_fun.named_parameters["verify_ssl"] = LogicalType::BOOLEAN; http_env_fun.named_parameters["http_proxy"] = LogicalType::VARCHAR; http_env_fun.named_parameters["http_proxy_password"] = LogicalType::VARCHAR; http_env_fun.named_parameters["http_proxy_username"] = LogicalType::VARCHAR; @@ -78,6 +80,7 @@ unique_ptr CreateHTTPSecretFunctions::CreateHTTPSecretFromEnv(Client } // Allow overwrites + secret->TrySetValue("verify_ssl", input); secret->TrySetValue("http_proxy", input); secret->TrySetValue("http_proxy_password", input); secret->TrySetValue("http_proxy_username", input); @@ -92,6 +95,7 @@ unique_ptr CreateHTTPSecretFunctions::CreateHTTPSecretFromConfig(Cli CreateSecretInput &input) { auto secret = make_uniq(input.scope, input.type, input.provider, input.name); + secret->TrySetValue("verify_ssl", input); secret->TrySetValue("http_proxy", input); secret->TrySetValue("http_proxy_password", input); secret->TrySetValue("http_proxy_username", input); diff --git a/src/duckdb/src/main/secret/secret.cpp b/src/duckdb/src/main/secret/secret.cpp index 9a39b7176..1e53afb14 100644 --- a/src/duckdb/src/main/secret/secret.cpp +++ b/src/duckdb/src/main/secret/secret.cpp @@ -163,6 +163,11 @@ void KeyValueSecretReader::Initialize(const char **secret_types, idx_t secret_ty } } +KeyValueSecretReader::KeyValueSecretReader(const KeyValueSecret &secret_p, FileOpener &opener_p) : secret(secret_p) { + db = opener_p.TryGetDatabase(); + context = opener_p.TryGetClientContext(); +} + KeyValueSecretReader::KeyValueSecretReader(FileOpener &opener_p, optional_ptr info, const char **secret_types, idx_t secret_types_len) { db = opener_p.TryGetDatabase(); diff --git a/src/duckdb/src/main/settings/autogenerated_settings.cpp b/src/duckdb/src/main/settings/autogenerated_settings.cpp index d15157226..83a8fc8ca 100644 --- a/src/duckdb/src/main/settings/autogenerated_settings.cpp +++ b/src/duckdb/src/main/settings/autogenerated_settings.cpp @@ -34,114 +34,11 @@ Value AccessModeSetting::GetSetting(const ClientContext &context) { return Value(StringUtil::Lower(EnumUtil::ToString(config.options.access_mode))); } -//===----------------------------------------------------------------------===// -// Allocator Background Threads -//===----------------------------------------------------------------------===// -void AllocatorBackgroundThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.allocator_background_threads = input.GetValue(); -} - -void AllocatorBackgroundThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.allocator_background_threads = DBConfigOptions().allocator_background_threads; -} - -Value AllocatorBackgroundThreadsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allocator_background_threads); -} - -//===----------------------------------------------------------------------===// -// Allow Community Extensions -//===----------------------------------------------------------------------===// -void AllowCommunityExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.allow_community_extensions = input.GetValue(); -} - -void AllowCommunityExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.allow_community_extensions = DBConfigOptions().allow_community_extensions; -} - -Value AllowCommunityExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_community_extensions); -} - //===----------------------------------------------------------------------===// // Allow Parser Override Extension //===----------------------------------------------------------------------===// -void AllowParserOverrideExtensionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.allow_parser_override_extension = input.GetValue(); -} - -void AllowParserOverrideExtensionSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.allow_parser_override_extension = DBConfigOptions().allow_parser_override_extension; -} - -Value AllowParserOverrideExtensionSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.allow_parser_override_extension); -} - -//===----------------------------------------------------------------------===// -// Allow Unredacted Secrets -//===----------------------------------------------------------------------===// -void AllowUnredactedSecretsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.allow_unredacted_secrets = input.GetValue(); -} - -void AllowUnredactedSecretsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.allow_unredacted_secrets = DBConfigOptions().allow_unredacted_secrets; -} - -Value AllowUnredactedSecretsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_unredacted_secrets); -} - -//===----------------------------------------------------------------------===// -// Allow Unsigned Extensions -//===----------------------------------------------------------------------===// -void AllowUnsignedExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.allow_unsigned_extensions = input.GetValue(); -} - -void AllowUnsignedExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.allow_unsigned_extensions = DBConfigOptions().allow_unsigned_extensions; -} - -Value AllowUnsignedExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_unsigned_extensions); +void AllowParserOverrideExtensionSetting::OnSet(SettingCallbackInfo &info, Value ¶meter) { + EnumUtil::FromString(StringValue::Get(parameter)); } //===----------------------------------------------------------------------===// @@ -151,54 +48,6 @@ void ArrowOutputVersionSetting::OnSet(SettingCallbackInfo &info, Value ¶mete EnumUtil::FromString(StringValue::Get(parameter)); } -//===----------------------------------------------------------------------===// -// Autoinstall Extension Repository -//===----------------------------------------------------------------------===// -void AutoinstallExtensionRepositorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.autoinstall_extension_repo = input.GetValue(); -} - -void AutoinstallExtensionRepositorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.autoinstall_extension_repo = DBConfigOptions().autoinstall_extension_repo; -} - -Value AutoinstallExtensionRepositorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.autoinstall_extension_repo); -} - -//===----------------------------------------------------------------------===// -// Autoinstall Known Extensions -//===----------------------------------------------------------------------===// -void AutoinstallKnownExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.autoinstall_known_extensions = input.GetValue(); -} - -void AutoinstallKnownExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.autoinstall_known_extensions = DBConfigOptions().autoinstall_known_extensions; -} - -Value AutoinstallKnownExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.autoinstall_known_extensions); -} - -//===----------------------------------------------------------------------===// -// Autoload Known Extensions -//===----------------------------------------------------------------------===// -void AutoloadKnownExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.autoload_known_extensions = input.GetValue(); -} - -void AutoloadKnownExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.autoload_known_extensions = DBConfigOptions().autoload_known_extensions; -} - -Value AutoloadKnownExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.autoload_known_extensions); -} - //===----------------------------------------------------------------------===// // Checkpoint Threshold //===----------------------------------------------------------------------===// @@ -206,22 +55,6 @@ void CheckpointThresholdSetting::ResetGlobal(DatabaseInstance *db, DBConfig &con config.options.checkpoint_wal_size = DBConfigOptions().checkpoint_wal_size; } -//===----------------------------------------------------------------------===// -// Custom Extension Repository -//===----------------------------------------------------------------------===// -void CustomExtensionRepositorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.custom_extension_repo = input.GetValue(); -} - -void CustomExtensionRepositorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.custom_extension_repo = DBConfigOptions().custom_extension_repo; -} - -Value CustomExtensionRepositorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.custom_extension_repo); -} - //===----------------------------------------------------------------------===// // Custom User Agent //===----------------------------------------------------------------------===// @@ -276,63 +109,10 @@ void DebugWindowModeSetting::OnSet(SettingCallbackInfo &info, Value ¶meter) } //===----------------------------------------------------------------------===// -// Disable Database Invalidation +// Deprecated Using Key Syntax //===----------------------------------------------------------------------===// -void DisableDatabaseInvalidationSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.disable_database_invalidation = input.GetValue(); -} - -void DisableDatabaseInvalidationSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.disable_database_invalidation = DBConfigOptions().disable_database_invalidation; -} - -Value DisableDatabaseInvalidationSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.disable_database_invalidation); -} - -//===----------------------------------------------------------------------===// -// Enable External Access -//===----------------------------------------------------------------------===// -void EnableExternalAccessSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.enable_external_access = input.GetValue(); -} - -void EnableExternalAccessSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.enable_external_access = DBConfigOptions().enable_external_access; -} - -Value EnableExternalAccessSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.enable_external_access); -} - -//===----------------------------------------------------------------------===// -// Enable H T T P Metadata Cache -//===----------------------------------------------------------------------===// -void EnableHTTPMetadataCacheSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.http_metadata_cache_enable = input.GetValue(); -} - -void EnableHTTPMetadataCacheSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_metadata_cache_enable = DBConfigOptions().http_metadata_cache_enable; -} - -Value EnableHTTPMetadataCacheSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.http_metadata_cache_enable); +void DeprecatedUsingKeySyntaxSetting::OnSet(SettingCallbackInfo &info, Value ¶meter) { + EnumUtil::FromString(StringValue::Get(parameter)); } //===----------------------------------------------------------------------===// @@ -358,203 +138,32 @@ Value EnableProgressBarSetting::GetSetting(const ClientContext &context) { return Value::BOOLEAN(config.enable_progress_bar); } -//===----------------------------------------------------------------------===// -// Errors As J S O N -//===----------------------------------------------------------------------===// -void ErrorsAsJSONSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.errors_as_json = input.GetValue(); -} - -void ErrorsAsJSONSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).errors_as_json = ClientConfig().errors_as_json; -} - -Value ErrorsAsJSONSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.errors_as_json); -} - //===----------------------------------------------------------------------===// // Explain Output //===----------------------------------------------------------------------===// -void ExplainOutputSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - auto str_input = StringUtil::Upper(input.GetValue()); - config.explain_output_type = EnumUtil::FromString(str_input); -} - -void ExplainOutputSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).explain_output_type = ClientConfig().explain_output_type; -} - -Value ExplainOutputSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(StringUtil::Lower(EnumUtil::ToString(config.explain_output_type))); -} - -//===----------------------------------------------------------------------===// -// Extension Directory -//===----------------------------------------------------------------------===// -void ExtensionDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.extension_directory = input.GetValue(); -} - -void ExtensionDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.extension_directory = DBConfigOptions().extension_directory; -} - -Value ExtensionDirectorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.extension_directory); -} - -//===----------------------------------------------------------------------===// -// External Threads -//===----------------------------------------------------------------------===// -void ExternalThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.external_threads = input.GetValue(); -} - -void ExternalThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.external_threads = DBConfigOptions().external_threads; -} - -Value ExternalThreadsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.external_threads); -} - -//===----------------------------------------------------------------------===// -// Home Directory -//===----------------------------------------------------------------------===// -void HomeDirectorySetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).home_directory = ClientConfig().home_directory; -} - -Value HomeDirectorySetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(config.home_directory); -} - -//===----------------------------------------------------------------------===// -// H T T P Proxy -//===----------------------------------------------------------------------===// -void HTTPProxySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.http_proxy = input.GetValue(); -} - -void HTTPProxySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_proxy = DBConfigOptions().http_proxy; -} - -Value HTTPProxySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.http_proxy); -} - -//===----------------------------------------------------------------------===// -// H T T P Proxy Password -//===----------------------------------------------------------------------===// -void HTTPProxyPasswordSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.http_proxy_password = input.GetValue(); -} - -void HTTPProxyPasswordSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_proxy_password = DBConfigOptions().http_proxy_password; -} - -Value HTTPProxyPasswordSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.http_proxy_password); -} - -//===----------------------------------------------------------------------===// -// H T T P Proxy Username -//===----------------------------------------------------------------------===// -void HTTPProxyUsernameSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.http_proxy_username = input.GetValue(); -} - -void HTTPProxyUsernameSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_proxy_username = DBConfigOptions().http_proxy_username; -} - -Value HTTPProxyUsernameSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.http_proxy_username); +void ExplainOutputSetting::OnSet(SettingCallbackInfo &info, Value ¶meter) { + EnumUtil::FromString(StringValue::Get(parameter)); } //===----------------------------------------------------------------------===// -// Lock Configuration +// Force Bitpacking Mode //===----------------------------------------------------------------------===// -void LockConfigurationSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.lock_configuration = input.GetValue(); -} - -void LockConfigurationSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.lock_configuration = DBConfigOptions().lock_configuration; -} - -Value LockConfigurationSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.lock_configuration); +void ForceBitpackingModeSetting::OnSet(SettingCallbackInfo &info, Value ¶meter) { + EnumUtil::FromString(StringValue::Get(parameter)); } //===----------------------------------------------------------------------===// -// Max Expression Depth +// Lambda Syntax //===----------------------------------------------------------------------===// -void MaxExpressionDepthSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.max_expression_depth = input.GetValue(); -} - -void MaxExpressionDepthSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).max_expression_depth = ClientConfig().max_expression_depth; -} - -Value MaxExpressionDepthSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.max_expression_depth); +void LambdaSyntaxSetting::OnSet(SettingCallbackInfo &info, Value ¶meter) { + EnumUtil::FromString(StringValue::Get(parameter)); } //===----------------------------------------------------------------------===// // Pin Threads //===----------------------------------------------------------------------===// -void PinThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto str_input = StringUtil::Upper(input.GetValue()); - config.options.pin_threads = EnumUtil::FromString(str_input); -} - -void PinThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.pin_threads = DBConfigOptions().pin_threads; -} - -Value PinThreadsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::Lower(EnumUtil::ToString(config.options.pin_threads))); -} - -//===----------------------------------------------------------------------===// -// Scheduler Process Partial -//===----------------------------------------------------------------------===// -void SchedulerProcessPartialSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.scheduler_process_partial = input.GetValue(); -} - -void SchedulerProcessPartialSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.scheduler_process_partial = DBConfigOptions().scheduler_process_partial; -} - -Value SchedulerProcessPartialSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.scheduler_process_partial); +void PinThreadsSetting::OnSet(SettingCallbackInfo &info, Value ¶meter) { + EnumUtil::FromString(StringValue::Get(parameter)); } //===----------------------------------------------------------------------===// @@ -571,36 +180,4 @@ void ValidateExternalFileCacheSetting::OnSet(SettingCallbackInfo &info, Value &p EnumUtil::FromString(StringValue::Get(parameter)); } -//===----------------------------------------------------------------------===// -// Variant Minimum Shredding Size -//===----------------------------------------------------------------------===// -void VariantMinimumShreddingSize::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.variant_minimum_shredding_size = input.GetValue(); -} - -void VariantMinimumShreddingSize::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.variant_minimum_shredding_size = DBConfigOptions().variant_minimum_shredding_size; -} - -Value VariantMinimumShreddingSize::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BIGINT(config.options.variant_minimum_shredding_size); -} - -//===----------------------------------------------------------------------===// -// Zstd Min String Length -//===----------------------------------------------------------------------===// -void ZstdMinStringLengthSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.zstd_min_string_length = input.GetValue(); -} - -void ZstdMinStringLengthSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.zstd_min_string_length = DBConfigOptions().zstd_min_string_length; -} - -Value ZstdMinStringLengthSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.zstd_min_string_length); -} - } // namespace duckdb diff --git a/src/duckdb/src/main/settings/custom_settings.cpp b/src/duckdb/src/main/settings/custom_settings.cpp index 9c5635815..67f6d9a45 100644 --- a/src/duckdb/src/main/settings/custom_settings.cpp +++ b/src/duckdb/src/main/settings/custom_settings.cpp @@ -12,7 +12,6 @@ #include "duckdb/main/settings.hpp" #include "duckdb/common/enums/access_mode.hpp" -#include "duckdb/common/enums/cache_validation_mode.hpp" #include "duckdb/common/enum_util.hpp" #include "duckdb/catalog/catalog_search_path.hpp" #include "duckdb/common/string_util.hpp" @@ -23,6 +22,7 @@ #include "duckdb/main/config.hpp" #include "duckdb/main/database.hpp" #include "duckdb/main/database_manager.hpp" +#include "duckdb/main/extension_helper.hpp" #include "duckdb/main/query_profiler.hpp" #include "duckdb/main/secret/secret_manager.hpp" #include "duckdb/parallel/task_scheduler.hpp" @@ -38,6 +38,8 @@ #include "duckdb/function/variant/variant_shredding.hpp" #include "duckdb/storage/block_allocator.hpp" +#include "mbedtls_wrapper.hpp" + namespace duckdb { constexpr const char *LoggingMode::Name; @@ -48,10 +50,6 @@ constexpr const char *EnabledLogTypes::Name; constexpr const char *DisabledLogTypes::Name; constexpr const char *DisabledFilesystemsSetting::Name; -const string GetDefaultUserAgent() { - return StringUtil::Format("duckdb/%s(%s)", DuckDB::LibraryVersion(), DuckDB::Platform()); -} - namespace { template @@ -78,18 +76,10 @@ bool AccessModeSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, cons //===----------------------------------------------------------------------===// // Allocator Background Threads //===----------------------------------------------------------------------===// -bool AllocatorBackgroundThreadsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorBackgroundThreads(input.GetValue()); - } - return true; -} - -bool AllocatorBackgroundThreadsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorBackgroundThreads(DBConfigOptions().allocator_background_threads); +void AllocatorBackgroundThreadsSetting::OnSet(SettingCallbackInfo &info, Value &input) { + if (info.db) { + TaskScheduler::GetScheduler(*info.db).SetAllocatorBackgroundThreads(input.GetValue()); } - return true; } //===----------------------------------------------------------------------===// @@ -143,46 +133,10 @@ Value AllocatorFlushThresholdSetting::GetSetting(const ClientContext &context) { //===----------------------------------------------------------------------===// // Allow Community Extensions //===----------------------------------------------------------------------===// -bool AllowCommunityExtensionsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db && !config.options.allow_community_extensions) { - auto new_value = input.GetValue(); - if (new_value) { - throw InvalidInputException("Cannot upgrade allow_community_extensions setting while database is running"); - } - return false; - } - return true; -} - -bool AllowCommunityExtensionsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db && !config.options.allow_community_extensions) { - if (DBConfigOptions().allow_community_extensions) { - throw InvalidInputException("Cannot upgrade allow_community_extensions setting while database is running"); - } - return false; - } - return true; -} - -//===----------------------------------------------------------------------===// -// Allow Parser Override -//===----------------------------------------------------------------------===// -bool AllowParserOverrideExtensionSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - vector supported_options = {"default", "fallback", "strict", "strict_when_supported"}; - string supported_option_string; - for (const auto &option : supported_options) { - if (StringUtil::CIEquals(new_value, option)) { - return true; - } +void AllowCommunityExtensionsSetting::OnSet(SettingCallbackInfo &info, Value &input) { + if (info.db && input.GetValue()) { + throw InvalidInputException("Cannot change allow_community_extensions setting while database is running"); } - throw InvalidInputException("Unrecognized value for parser override setting. Valid options are: %s", - StringUtil::Join(supported_options, ", ")); -} - -bool AllowParserOverrideExtensionSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - config.options.allow_parser_override_extension = "default"; - return true; } //===----------------------------------------------------------------------===// @@ -205,59 +159,35 @@ Value AllowPersistentSecretsSetting::GetSetting(const ClientContext &context) { //===----------------------------------------------------------------------===// // Allow Unredacted Secrets //===----------------------------------------------------------------------===// -bool AllowUnredactedSecretsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db && input.GetValue()) { - throw InvalidInputException("Cannot change allow_unredacted_secrets setting while database is running"); - } - return true; -} - -bool AllowUnredactedSecretsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db) { +void AllowUnredactedSecretsSetting::OnSet(SettingCallbackInfo &info, Value &input) { + if ((info.db || info.context) && input.GetValue()) { throw InvalidInputException("Cannot change allow_unredacted_secrets setting while database is running"); } - return true; } //===----------------------------------------------------------------------===// // Disable Database Invalidation //===----------------------------------------------------------------------===// -bool DisableDatabaseInvalidationSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db && input.GetValue()) { +void DisableDatabaseInvalidationSetting::OnSet(SettingCallbackInfo &info, Value &input) { + if (info.db || info.context) { throw InvalidInputException("Cannot change disable_database_invalidation setting while database is running"); } - return true; -} - -bool DisableDatabaseInvalidationSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change disable_database_invalidation setting while database is running"); - } - return true; } //===----------------------------------------------------------------------===// // Allow Unsigned Extensions //===----------------------------------------------------------------------===// -bool AllowUnsignedExtensionsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db && input.GetValue()) { +void AllowUnsignedExtensionsSetting::OnSet(SettingCallbackInfo &info, Value &input) { + if (info.db && input.GetValue()) { throw InvalidInputException("Cannot change allow_unsigned_extensions setting while database is running"); } - return true; -} - -bool AllowUnsignedExtensionsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change allow_unsigned_extensions setting while database is running"); - } - return true; } //===----------------------------------------------------------------------===// // Allowed Directories //===----------------------------------------------------------------------===// void AllowedDirectoriesSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!config.options.enable_external_access) { + if (!Settings::Get(config)) { throw InvalidInputException("Cannot change allowed_directories when enable_external_access is disabled"); } if (!config.file_system) { @@ -271,7 +201,7 @@ void AllowedDirectoriesSetting::SetGlobal(DatabaseInstance *db, DBConfig &config } void AllowedDirectoriesSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!config.options.enable_external_access) { + if (!Settings::Get(config)) { throw InvalidInputException("Cannot change allowed_directories when enable_external_access is disabled"); } config.options.allowed_directories = DBConfigOptions().allowed_directories; @@ -290,7 +220,7 @@ Value AllowedDirectoriesSetting::GetSetting(const ClientContext &context) { // Allowed Paths //===----------------------------------------------------------------------===//void void AllowedPathsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!config.options.enable_external_access) { + if (!Settings::Get(config)) { throw InvalidInputException("Cannot change allowed_paths when enable_external_access is disabled"); } if (!config.file_system) { @@ -305,7 +235,7 @@ void AllowedPathsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, cons } void AllowedPathsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!config.options.enable_external_access) { + if (!Settings::Get(config)) { throw InvalidInputException("Cannot change allowed_paths when enable_external_access is disabled"); } config.options.allowed_paths = DBConfigOptions().allowed_paths; @@ -581,19 +511,9 @@ void CustomUserAgentSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) //===----------------------------------------------------------------------===// // Default Block Size //===----------------------------------------------------------------------===// -void DefaultBlockSizeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { +void DefaultBlockSizeSetting::OnSet(SettingCallbackInfo &, Value &input) { auto block_alloc_size = input.GetValue(); Storage::VerifyBlockAllocSize(block_alloc_size); - config.options.default_block_alloc_size = block_alloc_size; -} - -void DefaultBlockSizeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.default_block_alloc_size = DBConfigOptions().default_block_alloc_size; -} - -Value DefaultBlockSizeSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.default_block_alloc_size); } //===----------------------------------------------------------------------===// @@ -674,12 +594,15 @@ void DisabledCompressionMethodsSetting::SetGlobal(DatabaseInstance *db, DBConfig disabled_compression_methods.clear(); break; } - auto compression_type = CompressionTypeFromString(param); - if (compression_type == CompressionType::COMPRESSION_UNCOMPRESSED) { - throw InvalidInputException("Uncompressed compression cannot be disabled"); - } - if (compression_type == CompressionType::COMPRESSION_AUTO) { - throw InvalidInputException("Unrecognized compression method \"%s\"", entry); + auto compression_type = EnumUtil::FromString(param); + switch (compression_type) { + case CompressionType::COMPRESSION_AUTO: + case CompressionType::COMPRESSION_CONSTANT: + case CompressionType::COMPRESSION_EMPTY: + case CompressionType::COMPRESSION_UNCOMPRESSED: + throw InvalidInputException("Compression method %s cannot be disabled", param); + default: + break; } disabled_compression_methods.push_back(compression_type); } @@ -759,83 +682,49 @@ Value DisabledOptimizersSetting::GetSetting(const ClientContext &context) { //===----------------------------------------------------------------------===// // Duckdb Api //===----------------------------------------------------------------------===// -void DuckDBAPISetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - if (db) { +void DuckDBAPISetting::OnSet(SettingCallbackInfo &info, Value &input) { + if (info.db) { throw InvalidInputException("Cannot change duckdb_api setting while database is running"); } - config.options.duckdb_api = new_value; -} - -void DuckDBAPISetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change duckdb_api setting while database is running"); - } - config.options.duckdb_api = GetDefaultUserAgent(); -} - -Value DuckDBAPISetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.duckdb_api); } //===----------------------------------------------------------------------===// // Enable External Access //===----------------------------------------------------------------------===// -bool EnableExternalAccessSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!db) { - return true; +void EnableExternalAccessSetting::OnSet(SettingCallbackInfo &info, Value &input) { + if (!info.db) { + return; } if (input.GetValue()) { - throw InvalidInputException("Cannot change enable_external_access setting while database is running"); + throw InvalidInputException("Cannot enable external access while database is running"); } - if (db && config.options.enable_external_access) { + auto &config = info.config; + if (info.db && Settings::Get(*info.db)) { // we are turning off external access - add any already attached databases to the list of accepted paths - auto &db_manager = DatabaseManager::Get(*db); + auto &db_manager = DatabaseManager::Get(*info.db); auto attached_paths = db_manager.GetAttachedDatabasePaths(); for (auto &path : attached_paths) { config.AddAllowedPath(path); config.AddAllowedPath(path + ".wal"); - config.AddAllowedPath(path + ".checkpoint.wal"); - config.AddAllowedPath(path + ".recovery.wal"); + config.AddAllowedPath(path + ".wal.checkpoint"); + config.AddAllowedPath(path + ".wal.recovery"); } } if (config.options.use_temporary_directory && !config.options.temporary_directory.empty()) { // if temp directory is enabled we can also write there config.AddAllowedDirectory(config.options.temporary_directory); } - return true; -} - -bool EnableExternalAccessSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change enable_external_access setting while database is running"); - } - return true; } //===----------------------------------------------------------------------===// // Enable External File Cache //===----------------------------------------------------------------------===// -void EnableExternalFileCacheSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.enable_external_file_cache = input.GetValue(); - if (db) { - ExternalFileCache::Get(*db).SetEnabled(config.options.enable_external_file_cache); - } -} - -void EnableExternalFileCacheSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.enable_external_file_cache = DBConfigOptions().enable_external_file_cache; - if (db) { - ExternalFileCache::Get(*db).SetEnabled(config.options.enable_external_file_cache); +void EnableExternalFileCacheSetting::OnSet(SettingCallbackInfo &info, Value &input) { + if (info.db) { + ExternalFileCache::Get(*info.db).SetEnabled(input.GetValue()); } } -Value EnableExternalFileCacheSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.enable_external_file_cache); -} - //===----------------------------------------------------------------------===// // Enable Logging //===----------------------------------------------------------------------===// @@ -864,7 +753,12 @@ void ForceVariantShredding::SetGlobal(DatabaseInstance *_, DBConfig &config, con value.type().ToString()); } - auto logical_type = TransformStringToLogicalType(value.GetValue()); + auto logical_type = UnboundType::TryParseAndDefaultBind(value.GetValue()); + if (logical_type.id() == LogicalTypeId::INVALID) { + throw InvalidInputException("Could not parse the argument '%s' to 'force_variant_shredding' as a built in type", + value.GetValue()); + } + TypeVisitor::Contains(logical_type, [](const LogicalType &type) { if (type.IsNested()) { if (type.id() != LogicalTypeId::STRUCT && type.id() != LogicalTypeId::LIST) { @@ -916,7 +810,7 @@ void ForceVariantShredding::SetGlobal(DatabaseInstance *_, DBConfig &config, con }); auto shredding_type = TypeVisitor::VisitReplace(logical_type, [](const LogicalType &type) { - return LogicalType::STRUCT({{"untyped_value_index", LogicalType::UINTEGER}, {"typed_value", type}}); + return LogicalType::STRUCT({{"typed_value", type}, {"untyped_value_index", LogicalType::UINTEGER}}); }); force_variant_shredding = LogicalType::STRUCT({{"unshredded", VariantShredding::GetUnshreddedType()}, {"shredded", shredding_type}}); @@ -1178,76 +1072,26 @@ bool EnableProgressBarSetting::OnLocalReset(ClientContext &context) { //===----------------------------------------------------------------------===// // External Threads //===----------------------------------------------------------------------===// -bool ExternalThreadsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_val = input.GetValue(); - if (new_val < 0) { - throw SyntaxException("Must have a non-negative number of external threads!"); - } - auto new_external_threads = NumericCast(new_val); - if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(config.options.maximum_threads, new_external_threads); - } - return true; -} - -bool ExternalThreadsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - idx_t new_external_threads = DBConfigOptions().external_threads; - if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(config.options.maximum_threads, new_external_threads); - } - return true; -} - -//===----------------------------------------------------------------------===// -// File Search Path -//===----------------------------------------------------------------------===// -void FileSearchPathSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = input.ToString(); - auto &client_data = ClientData::Get(context); - client_data.file_search_path = parameter; -} - -void FileSearchPathSetting::ResetLocal(ClientContext &context) { - auto &client_data = ClientData::Get(context); - client_data.file_search_path.clear(); -} - -Value FileSearchPathSetting::GetSetting(const ClientContext &context) { - auto &client_data = ClientData::Get(context); - return Value(client_data.file_search_path); -} - -//===----------------------------------------------------------------------===// -// Force Bitpacking Mode -//===----------------------------------------------------------------------===// -void ForceBitpackingModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto mode_str = StringUtil::Lower(input.ToString()); - auto mode = BitpackingModeFromString(mode_str); - if (mode == BitpackingMode::INVALID) { - throw ParserException("Unrecognized option for force_bitpacking_mode, expected none, constant, constant_delta, " - "delta_for, or for"); +void ExternalThreadsSetting::OnSet(SettingCallbackInfo &info, Value &input) { + auto new_external_threads = input.GetValue(); + if (info.db) { + TaskScheduler::GetScheduler(*info.db).SetThreads(info.config.options.maximum_threads, new_external_threads); } - config.options.force_bitpacking_mode = mode; -} - -void ForceBitpackingModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.force_bitpacking_mode = DBConfigOptions().force_bitpacking_mode; -} - -Value ForceBitpackingModeSetting::GetSetting(const ClientContext &context) { - return Value(BitpackingModeToString(context.db->config.options.force_bitpacking_mode)); } //===----------------------------------------------------------------------===// // Force Compression //===----------------------------------------------------------------------===// -void ForceCompressionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { +void ForceCompressionSetting::OnSet(SettingCallbackInfo &info, Value &input) { auto compression = StringUtil::Lower(input.ToString()); if (compression == "none" || compression == "auto") { - config.options.force_compression = CompressionType::COMPRESSION_AUTO; + input = "auto"; } else { - auto compression_type = CompressionTypeFromString(compression); - //! FIXME: do we want to try to retrieve the AttachedDatabase here to get the StorageManager ?? + auto compression_type = EnumUtil::FromString(compression); + if (compression_type == CompressionType::COMPRESSION_CONSTANT || + compression_type == CompressionType::COMPRESSION_EMPTY) { + throw ParserException("auto / constant cannot be used for force_compression"); + } auto compression_availability_result = CompressionTypeIsAvailable(compression_type); if (!compression_availability_result.IsAvailable()) { if (compression_availability_result.IsDeprecated()) { @@ -1258,32 +1102,27 @@ void ForceCompressionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, CompressionTypeToString(compression_type)); } } - if (compression_type == CompressionType::COMPRESSION_AUTO) { - auto compression_types = StringUtil::Join(ListCompressionTypes(), ", "); - throw ParserException("Unrecognized option for PRAGMA force_compression, expected %s", compression_types); - } - config.options.force_compression = compression_type; } } -void ForceCompressionSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.force_compression = DBConfigOptions().force_compression; -} - -Value ForceCompressionSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(*context.db); - return CompressionTypeToString(config.options.force_compression); -} - //===----------------------------------------------------------------------===// // Home Directory //===----------------------------------------------------------------------===// -void HomeDirectorySetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - if (!input.IsNull() && FileSystem::GetFileSystem(context).IsRemoteFile(input.ToString())) { - throw InvalidInputException("Cannot set the home directory to a remote path"); +void HomeDirectorySetting::OnSet(SettingCallbackInfo &info, Value &input) { + optional_ptr fs; + if (info.context) { + fs = FileSystem::GetFileSystem(*info.context); + } else if (info.db) { + fs = FileSystem::GetFileSystem(*info.db); + } else { + fs = info.config.file_system.get(); + } + if (fs && !input.IsNull()) { + auto new_home_directory = input.ToString(); + if (fs->IsRemoteFile(new_home_directory)) { + throw InvalidInputException("Cannot set the home directory to a remote path"); + } } - config.home_directory = input.IsNull() ? string() : input.ToString(); } //===----------------------------------------------------------------------===// @@ -1317,6 +1156,44 @@ Value EnableHTTPLoggingSetting::GetSetting(const ClientContext &context) { return Value::BOOLEAN(config.enable_http_logging); } +//===----------------------------------------------------------------------===// +// Enable Mbedtls +//===----------------------------------------------------------------------===// + +void ForceMbedtlsUnsafeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.force_mbedtls = input.GetValue(); + + if (!config.options.force_mbedtls) { + // check if there are attached databases encrypted that are not read only + bool encrypted_db_attached = false; + for (auto &database : db->GetDatabaseManager().GetDatabases()) { + if (database->HasStorageManager() && database->GetStorageManager().IsEncrypted() && + !database->IsReadOnly()) { + encrypted_db_attached = true; + break; + }; + }; + + if (encrypted_db_attached) { + // autoload httpfs if any attached db uses encryption + if (!ExtensionHelper::TryAutoLoadExtension(*db, "httpfs")) { + throw InvalidConfigurationException("Failed to autoload HTTPFS. Cannot disable MbedTLS, HTTPFS " + "extension is required to write encrypted databases."); + }; + } + } +} + +void ForceMbedtlsUnsafeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + // If encryption is initialized, httpfs will be attempted to autoload again + SetGlobal(db, config, false); +} + +Value ForceMbedtlsUnsafeSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.force_mbedtls); +} + //===----------------------------------------------------------------------===// // H T T P Logging Output //===----------------------------------------------------------------------===// @@ -1345,50 +1222,24 @@ void IndexScanPercentageSetting::OnSet(SettingCallbackInfo &, Value &input) { } } -//===----------------------------------------------------------------------===// -// Lambda Syntax Setting -//===----------------------------------------------------------------------===// -void LambdaSyntaxSetting::SetLocal(ClientContext &context, const Value &input) { - auto setting_type = EnumUtil::FromString(input.ToString()); - auto &config = ClientConfig::GetConfig(context); - config.lambda_syntax = setting_type; -} - -void LambdaSyntaxSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - config.lambda_syntax = LambdaSyntax::DEFAULT; -} - -Value LambdaSyntaxSetting::GetSetting(const ClientContext &context) { - const auto &config = ClientConfig::GetConfig(context); - return Value(EnumUtil::ToString(config.lambda_syntax)); -} - //===----------------------------------------------------------------------===// // Log Query Path //===----------------------------------------------------------------------===// -void LogQueryPathSetting::SetLocal(ClientContext &context, const Value &input) { - auto &client_data = ClientData::Get(context); +void LogQueryPathSetting::OnSet(SettingCallbackInfo &info, Value &input) { + if (!info.context) { + throw InvalidInputException("log_query_path can only be set when a context is present"); + } + auto &client_data = ClientData::Get(*info.context); auto path = input.ToString(); if (path.empty()) { // empty path: clean up query writer client_data.log_query_writer = nullptr; } else { - client_data.log_query_writer = make_uniq(FileSystem::GetFileSystem(context), path, + client_data.log_query_writer = make_uniq(FileSystem::GetFileSystem(*info.context), path, BufferedFileWriter::DEFAULT_OPEN_FLAGS); } } -void LogQueryPathSetting::ResetLocal(ClientContext &context) { - auto &client_data = ClientData::Get(context); - client_data.log_query_writer = nullptr; -} - -Value LogQueryPathSetting::GetSetting(const ClientContext &context) { - auto &client_data = ClientData::Get(context); - return client_data.log_query_writer ? Value(client_data.log_query_writer->path) : Value(); -} - //===----------------------------------------------------------------------===// // Max Memory //===----------------------------------------------------------------------===// @@ -1467,21 +1318,6 @@ void OrderedAggregateThresholdSetting::OnSet(SettingCallbackInfo &info, Value &i } } -//===----------------------------------------------------------------------===// -// Password -//===----------------------------------------------------------------------===// -void PasswordSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - // nop -} - -void PasswordSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - // nop -} - -Value PasswordSetting::GetSetting(const ClientContext &context) { - return Value(); -} - //===----------------------------------------------------------------------===// // Perfect Ht Threshold //===----------------------------------------------------------------------===// @@ -1719,7 +1555,7 @@ Value StreamingBufferSizeSetting::GetSetting(const ClientContext &context) { // Temp Directory //===----------------------------------------------------------------------===// void TempDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!config.options.enable_external_access) { + if (!Settings::Get(config)) { throw PermissionException("Modifying the temp_directory has been disabled by configuration"); } config.options.temporary_directory = input.IsNull() ? "" : input.ToString(); @@ -1731,7 +1567,7 @@ void TempDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, con } void TempDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!config.options.enable_external_access) { + if (!Settings::Get(config)) { throw PermissionException("Modifying the temp_directory has been disabled by configuration"); } config.SetDefaultTempDirectory(); @@ -1750,44 +1586,15 @@ Value TempDirectorySetting::GetSetting(const ClientContext &context) { //===----------------------------------------------------------------------===// // Temporary File Encryption //===----------------------------------------------------------------------===// -void TempFileEncryptionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto setting = input.GetValue(); - if (config.options.temp_file_encryption == setting) { - // setting is the current setting +void TempFileEncryptionSetting::OnSet(SettingCallbackInfo &info, Value &input) { + if (!info.db) { return; } - - if (db) { - auto &buffer_manager = BufferManager::GetBufferManager(*db); - if (buffer_manager.HasFilesInTemporaryDirectory()) { - throw PermissionException("Existing temporary files found: Modifying the temp_file_encryption setting " - "while there are existing temporary files is disabled."); - } + auto &buffer_manager = BufferManager::GetBufferManager(*info.db); + if (buffer_manager.HasFilesInTemporaryDirectory()) { + throw PermissionException("Existing temporary files found: Modifying the temp_file_encryption setting " + "while there are existing temporary files is disabled."); } - - config.options.temp_file_encryption = setting; -} - -void TempFileEncryptionSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (config.options.temp_file_encryption == true) { - // setting is the current setting - return; - } - - if (db) { - auto &buffer_manager = BufferManager::GetBufferManager(*db); - if (buffer_manager.HasFilesInTemporaryDirectory()) { - throw PermissionException("Existing temporary files found: Modifying the temp_file_encryption setting " - "while there are existing temporary files is disabled."); - } - } - - config.options.temp_file_encryption = true; -} - -Value TempFileEncryptionSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.temp_file_encryption); } //===----------------------------------------------------------------------===// @@ -1800,7 +1607,7 @@ void ThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Val } auto new_maximum_threads = NumericCast(new_val); if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, config.options.external_threads); + TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, Settings::Get(config)); } config.options.maximum_threads = new_maximum_threads; } @@ -1808,7 +1615,7 @@ void ThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Val void ThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { idx_t new_maximum_threads = config.GetSystemMaxThreads(*config.file_system); if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, config.options.external_threads); + TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, Settings::Get(config)); } config.options.maximum_threads = new_maximum_threads; } @@ -1819,18 +1626,16 @@ Value ThreadsSetting::GetSetting(const ClientContext &context) { } //===----------------------------------------------------------------------===// -// Username +// Warnings As Errors //===----------------------------------------------------------------------===// -void UsernameSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - // nop -} -void UsernameSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - // nop -} - -Value UsernameSetting::GetSetting(const ClientContext &context) { - return Value(); +void WarningsAsErrorsSetting::OnSet(SettingCallbackInfo &info, Value &input) { + auto &log_manager = LogManager::Get(*info.context); + if (input == Value(true) && !log_manager.GetConfig().enabled) { + throw Exception( + ExceptionType::SETTINGS, + "Can not set 'warnings_as_errors=true'; no logger is available. To solve, run: 'SET enable_logging=true;'"); + } } } // namespace duckdb diff --git a/src/duckdb/src/main/settings/settings.cpp b/src/duckdb/src/main/settings/settings.cpp new file mode 100644 index 000000000..3ab1a7d4a --- /dev/null +++ b/src/duckdb/src/main/settings/settings.cpp @@ -0,0 +1,20 @@ +#include "duckdb/main/settings.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/main/config.hpp" + +namespace duckdb { + +bool Settings::TryGetSettingInternal(const ClientContext &context, idx_t setting_index, Value &result) { + return context.TryGetCurrentUserSetting(setting_index, result); +} + +bool Settings::TryGetSettingInternal(const DBConfig &config, idx_t setting_index, Value &result) { + auto lookup_result = config.TryGetCurrentUserSetting(setting_index, result); + return lookup_result; +} + +bool Settings::TryGetSettingInternal(const DatabaseInstance &db, idx_t setting_index, Value &result) { + return TryGetSettingInternal(DBConfig::GetConfig(db), setting_index, result); +} + +} // namespace duckdb diff --git a/src/duckdb/src/main/user_settings.cpp b/src/duckdb/src/main/user_settings.cpp new file mode 100644 index 000000000..2f01704b2 --- /dev/null +++ b/src/duckdb/src/main/user_settings.cpp @@ -0,0 +1,186 @@ +#include "duckdb/main/user_settings.hpp" +#include "duckdb/main/settings.hpp" +#include "duckdb/common/types/string.hpp" + +namespace duckdb { + +void UserSettingsMap::SetUserSetting(idx_t setting_index, Value target_value) { + if (setting_index >= settings.size()) { + settings.resize(setting_index + 1); + } + auto &generic_setting = settings[setting_index]; + generic_setting.is_set = true; + generic_setting.value = std::move(target_value); +} + +void UserSettingsMap::ClearSetting(idx_t setting_index) { + if (setting_index >= settings.size()) { + // never set + return; + } + auto &generic_setting = settings[setting_index]; + generic_setting.is_set = false; + generic_setting.value = Value(); +} + +bool UserSettingsMap::IsSet(idx_t setting_index) const { + if (setting_index >= settings.size()) { + // never set + return false; + } + return settings[setting_index].is_set; +} + +bool UserSettingsMap::TryGetSetting(idx_t setting_index, Value &result_value) const { + if (setting_index >= settings.size()) { + // never set + return false; + } + auto &generic_setting = settings[setting_index]; + if (!generic_setting.is_set) { + return false; + } + result_value = generic_setting.value; + return true; +} + +//===--------------------------------------------------------------------===// +// GlobalUserSettings +//===--------------------------------------------------------------------===// +GlobalUserSettings::GlobalUserSettings() : settings_version(0) { +} + +GlobalUserSettings::GlobalUserSettings(const GlobalUserSettings &other) + : settings_map(other.settings_map), extension_parameters(other.extension_parameters), + settings_version(other.settings_version.load()) { +} + +GlobalUserSettings &GlobalUserSettings::operator=(const GlobalUserSettings &other) { + settings_map = other.settings_map; + extension_parameters = other.extension_parameters; + settings_version = other.settings_version.load(); + return *this; +} + +void GlobalUserSettings::SetUserSetting(idx_t setting_index, Value target_value) { + lock_guard guard(lock); + settings_map.SetUserSetting(setting_index, std::move(target_value)); + ++settings_version; +} + +void GlobalUserSettings::ClearSetting(idx_t setting_index) { + lock_guard guard(lock); + settings_map.ClearSetting(setting_index); + ++settings_version; +} + +bool GlobalUserSettings::IsSet(idx_t setting_index) const { + lock_guard guard(lock); + return settings_map.IsSet(setting_index); +} + +SettingLookupResult GlobalUserSettings::TryGetSetting(idx_t setting_index, Value &result_value) const { +#ifndef __MINGW32__ + // look-up in global settings + const auto &cache = GetSettings(); + if (cache.settings.TryGetSetting(setting_index, result_value)) { + return SettingLookupResult(SettingScope::GLOBAL); + } +#else + lock_guard guard(lock); + if (settings_map.TryGetSetting(setting_index, result_value)) { + return SettingLookupResult(SettingScope::GLOBAL); + } +#endif + + return SettingLookupResult(); +} + +bool GlobalUserSettings::HasExtensionOption(const string &name) const { + lock_guard l(lock); + return extension_parameters.find(name) != extension_parameters.end(); +} + +idx_t GlobalUserSettings::AddExtensionOption(const string &name, ExtensionOption extension_option) { + lock_guard l(lock); + const auto new_option = extension_parameters.emplace(make_pair(name, std::move(extension_option))); + const auto did_insert = new_option.second; + auto &option = new_option.first->second; + + if (!did_insert) { + return option.setting_index.GetIndex(); + } + + auto setting_index = GeneratedSettingInfo::MaxSettingIndex + extension_parameters.size() - 1; + option.setting_index = setting_index; + ++settings_version; + return setting_index; +} + +case_insensitive_map_t GlobalUserSettings::GetExtensionSettings() const { + lock_guard l(lock); + return extension_parameters; +} + +bool GlobalUserSettings::TryGetExtensionOption(const String &name, ExtensionOption &result) const { + lock_guard l(lock); + auto entry = extension_parameters.find(name.ToStdString()); + if (entry == extension_parameters.end()) { + return false; + } + result = entry->second; + return true; +} + +#ifndef __MINGW32__ +CachedGlobalSettings &GlobalUserSettings::GetSettings() const { + // Cache of global settings - used to allow lock-free access to global settings in a thread-safe manner + thread_local CachedGlobalSettings current_cache; + + const auto current_version = settings_version.load(std::memory_order_relaxed); + if (!current_cache.global_user_settings || this != current_cache.global_user_settings.get() || + current_cache.version != current_version) { + // out-of-date, refresh the cache + lock_guard guard(lock); + current_cache = CachedGlobalSettings(*this, settings_version, settings_map); + } + return current_cache; +} + +CachedGlobalSettings::CachedGlobalSettings() : version(0) { +} + +CachedGlobalSettings::CachedGlobalSettings(const GlobalUserSettings &global_user_settings_p, idx_t version, + UserSettingsMap settings_p) + : global_user_settings(global_user_settings_p), version(version), settings(std::move(settings_p)) { +} +#endif + +//===--------------------------------------------------------------------===// +// LocalUserSettings +//===--------------------------------------------------------------------===// +LocalUserSettings::~LocalUserSettings() { +} + +void LocalUserSettings::SetUserSetting(idx_t setting_index, Value target_value) { + settings_map.SetUserSetting(setting_index, std::move(target_value)); +} + +void LocalUserSettings::ClearSetting(idx_t setting_index) { + settings_map.ClearSetting(setting_index); +} + +bool LocalUserSettings::IsSet(idx_t setting_index) const { + return settings_map.IsSet(setting_index); +} + +SettingLookupResult LocalUserSettings::TryGetSetting(const GlobalUserSettings &global_settings, idx_t setting_index, + Value &result_value) const { + if (settings_map.TryGetSetting(setting_index, result_value)) { + return SettingLookupResult(SettingScope::LOCAL); + } + // look-up in global settings + return global_settings.TryGetSetting(setting_index, result_value); +} + +} // namespace duckdb diff --git a/src/duckdb/src/main/valid_checker.cpp b/src/duckdb/src/main/valid_checker.cpp index d3fcd5bff..4afa56aaf 100644 --- a/src/duckdb/src/main/valid_checker.cpp +++ b/src/duckdb/src/main/valid_checker.cpp @@ -1,6 +1,5 @@ #include "duckdb/main/valid_checker.hpp" - -#include "duckdb/main/database.hpp" +#include "duckdb/main/settings.hpp" namespace duckdb { @@ -14,7 +13,7 @@ void ValidChecker::Invalidate(string error) { } bool ValidChecker::IsInvalidated() { - if (db.config.options.disable_database_invalidation) { + if (Settings::Get(db)) { return false; } return is_invalidated; diff --git a/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp b/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp index b5c422133..b4e92b7cd 100644 --- a/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp +++ b/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp @@ -230,7 +230,7 @@ void BuildProbeSideOptimizer::VisitOperator(LogicalOperator &op) { // if the conditions have no equality, do not flip the children. // There is no physical join operator (yet) that can do an inequality right_semi/anti join. idx_t has_range = 0; - bool prefer_range_joins = DBConfig::GetSetting(context); + bool prefer_range_joins = Settings::Get(context); if (op.type == LogicalOperatorType::LOGICAL_ANY_JOIN || (op.Cast().HasEquality(has_range) && !prefer_range_joins)) { TryFlipJoinChildren(join); diff --git a/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp b/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp index 7098caae4..e31e9b445 100644 --- a/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp +++ b/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp @@ -13,6 +13,7 @@ #include "duckdb/planner/operator/logical_order.hpp" #include "duckdb/planner/operator/logical_projection.hpp" #include "duckdb/main/settings.hpp" +#include "duckdb/planner/binder.hpp" namespace duckdb { @@ -82,7 +83,7 @@ void ColumnLifetimeAnalyzer::VisitOperator(LogicalOperator &op) { // FIXME: for now, we only push into the projection map for equality (hash) joins idx_t has_range = 0; - bool prefer_range_joins = DBConfig::GetSetting(optimizer.context); + bool prefer_range_joins = Settings::Get(optimizer.context); if (!comp_join.HasEquality(has_range) || prefer_range_joins) { return; } diff --git a/src/duckdb/src/optimizer/expression_heuristics.cpp b/src/duckdb/src/optimizer/expression_heuristics.cpp index 766ac8d88..0bba42962 100644 --- a/src/duckdb/src/optimizer/expression_heuristics.cpp +++ b/src/duckdb/src/optimizer/expression_heuristics.cpp @@ -222,7 +222,7 @@ idx_t ExpressionHeuristics::Cost(Expression &expr) { return 1000; } -idx_t ExpressionHeuristics::Cost(TableFilter &filter) { +idx_t ExpressionHeuristics::Cost(const TableFilter &filter) { switch (filter.filter_type) { case TableFilterType::DYNAMIC_FILTER: case TableFilterType::OPTIONAL_FILTER: diff --git a/src/duckdb/src/optimizer/filter_combiner.cpp b/src/duckdb/src/optimizer/filter_combiner.cpp index e2480b963..9b2f426c6 100644 --- a/src/duckdb/src/optimizer/filter_combiner.cpp +++ b/src/duckdb/src/optimizer/filter_combiner.cpp @@ -354,6 +354,10 @@ FilterPushdownResult FilterCombiner::TryPushdownConstantFilter(TableFilterSet &t if (!TryGetBoundColumnIndex(column_ids, expr, column_index)) { return FilterPushdownResult::NO_PUSHDOWN; } + if (column_index.IsPushdownExtract()) { + //! FIXME: can't push down filters on a column that has a pushed down extract currently + return FilterPushdownResult::NO_PUSHDOWN; + } auto &constant_list = constant_values.find(equiv_set)->second; for (auto &constant_cmp : constant_list) { @@ -400,6 +404,10 @@ FilterPushdownResult FilterCombiner::TryPushdownGenericExpression(LogicalGet &ge auto &column_ids = get.GetColumnIds(); auto expr_filter = make_uniq(std::move(filter_expr)); auto &column_index = column_ids[bindings[0].column_index]; + if (column_index.IsPushdownExtract()) { + //! FIXME: can't support filters on a pushed down extract currently + return FilterPushdownResult::NO_PUSHDOWN; + } get.table_filters.PushFilter(column_index, std::move(expr_filter)); return FilterPushdownResult::PUSHED_DOWN_FULLY; } @@ -426,6 +434,10 @@ FilterPushdownResult FilterCombiner::TryPushdownPrefixFilter(TableFilterSet &tab return FilterPushdownResult::NO_PUSHDOWN; } auto &column_index = column_ids[column_ref.binding.column_index]; + if (column_index.IsPushdownExtract()) { + //! FIXME: can't support filter pushdown on pushed down extract currently + return FilterPushdownResult::NO_PUSHDOWN; + } //! Replace prefix with a set of comparisons auto lower_bound = make_uniq(ExpressionType::COMPARE_GREATERTHANOREQUALTO, Value(prefix_string)); table_filters.PushFilter(column_index, std::move(lower_bound)); @@ -457,6 +469,11 @@ FilterPushdownResult FilterCombiner::TryPushdownLikeFilter(TableFilterSet &table auto &column_ref = func.children[0]->Cast(); auto &constant_value_expr = func.children[1]->Cast(); auto &column_index = column_ids[column_ref.binding.column_index]; + if (column_index.IsPushdownExtract()) { + //! FIXME: can't support filter pushdown on pushed down extract currently + return FilterPushdownResult::NO_PUSHDOWN; + } + // constant value expr can sometimes be null. if so, push is not null filter, which will // make the filter unsatisfiable and return no results. if (constant_value_expr.value.IsNull()) { @@ -508,6 +525,11 @@ FilterPushdownResult FilterCombiner::TryPushdownInFilter(TableFilterSet &table_f } auto &column_ref = func.children[0]->Cast(); auto &column_index = column_ids[column_ref.binding.column_index]; + if (column_index.IsPushdownExtract()) { + //! FIXME: can't support filter pushdown on pushed down extract currently + return FilterPushdownResult::NO_PUSHDOWN; + } + //! check if all children are const expr bool children_constant = true; for (size_t i {1}; i < func.children.size(); i++) { @@ -603,6 +625,10 @@ FilterPushdownResult FilterCombiner::TryPushdownOrClause(TableFilterSet &table_f if (i == 0) { auto &col_id = column_ids[column_ref->binding.column_index]; column_id = col_id.GetPrimaryIndex(); + if (col_id.IsPushdownExtract()) { + //! FIXME: can't support filter pushdown on pushed down extract currently + return FilterPushdownResult::NO_PUSHDOWN; + } } else if (column_id != column_ids[column_ref->binding.column_index].GetPrimaryIndex()) { return FilterPushdownResult::NO_PUSHDOWN; } diff --git a/src/duckdb/src/optimizer/filter_pushdown.cpp b/src/duckdb/src/optimizer/filter_pushdown.cpp index 7c13386d9..1c1251f8c 100644 --- a/src/duckdb/src/optimizer/filter_pushdown.cpp +++ b/src/duckdb/src/optimizer/filter_pushdown.cpp @@ -9,6 +9,7 @@ #include "duckdb/planner/operator/logical_projection.hpp" #include "duckdb/planner/operator/logical_empty_result.hpp" #include "duckdb/planner/operator/logical_window.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" namespace duckdb { diff --git a/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp b/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp index 767b918c4..39e60bd69 100644 --- a/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +++ b/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp @@ -7,6 +7,7 @@ #include "duckdb/optimizer/join_order/plan_enumerator.hpp" #include "duckdb/planner/expression/list.hpp" #include "duckdb/planner/operator/list.hpp" +#include "duckdb/main/settings.hpp" namespace duckdb { @@ -25,7 +26,8 @@ JoinOrderOptimizer JoinOrderOptimizer::CreateChildOptimizer() { unique_ptr JoinOrderOptimizer::Optimize(unique_ptr plan, optional_ptr stats) { - if (depth > query_graph_manager.context.config.max_expression_depth) { + auto max_expression_depth = Settings::Get(query_graph_manager.context); + if (depth > max_expression_depth) { // Very deep plans will eventually consume quite some stack space // Returning the current plan is always a valid choice return plan; diff --git a/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp b/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp index ec39dbd05..07f103925 100644 --- a/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp +++ b/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp @@ -470,7 +470,7 @@ void PlanEnumerator::InitLeafPlans() { // Moerkotte and Thomas Neumannn, see that paper for additional info/documentation bonus slides: // https://db.in.tum.de/teaching/ws1415/queryopt/chapter3.pdf?lang=de void PlanEnumerator::SolveJoinOrder() { - bool force_no_cross_product = DBConfig::GetSetting(query_graph_manager.context); + bool force_no_cross_product = Settings::Get(query_graph_manager.context); // first try to solve the join order exactly if (query_graph_manager.relation_manager.NumRelations() >= THRESHOLD_TO_SWAP_TO_APPROXIMATE) { SolveJoinOrderApproximately(); diff --git a/src/duckdb/src/optimizer/join_order/relation_statistics_helper.cpp b/src/duckdb/src/optimizer/join_order/relation_statistics_helper.cpp index 2db600c7a..b78341240 100644 --- a/src/duckdb/src/optimizer/join_order/relation_statistics_helper.cpp +++ b/src/duckdb/src/optimizer/join_order/relation_statistics_helper.cpp @@ -443,7 +443,7 @@ RelationStats RelationStatisticsHelper::ExtractEmptyResultStats(LogicalEmptyResu return stats; } -idx_t RelationStatisticsHelper::InspectTableFilter(idx_t cardinality, idx_t column_index, TableFilter &filter, +idx_t RelationStatisticsHelper::InspectTableFilter(idx_t cardinality, idx_t column_index, const TableFilter &filter, BaseStatistics &base_stats) { auto cardinality_after_filters = cardinality; switch (filter.filter_type) { diff --git a/src/duckdb/src/optimizer/late_materialization.cpp b/src/duckdb/src/optimizer/late_materialization.cpp index 3b19b3612..6d1a06d9b 100644 --- a/src/duckdb/src/optimizer/late_materialization.cpp +++ b/src/duckdb/src/optimizer/late_materialization.cpp @@ -21,7 +21,7 @@ namespace duckdb { LateMaterialization::LateMaterialization(Optimizer &optimizer) : optimizer(optimizer) { - max_row_count = DBConfig::GetSetting(optimizer.context); + max_row_count = Settings::Get(optimizer.context); } vector LateMaterialization::ConstructRHS(unique_ptr &op) { @@ -371,7 +371,7 @@ bool LateMaterialization::TryLateMaterialization(unique_ptr &op } bool LateMaterialization::OptimizeLargeLimit(LogicalLimit &limit, idx_t limit_val, bool has_offset) { - if (!has_offset && !DBConfig::GetSetting(optimizer.context)) { + if (!has_offset && !Settings::Get(optimizer.context)) { // we avoid optimizing large limits if preserve insertion order is false // since the limit is executed in parallel anyway return false; diff --git a/src/duckdb/src/optimizer/optimizer.cpp b/src/duckdb/src/optimizer/optimizer.cpp index 97585c1f0..c2c4540c1 100644 --- a/src/duckdb/src/optimizer/optimizer.cpp +++ b/src/duckdb/src/optimizer/optimizer.cpp @@ -39,6 +39,7 @@ #include "duckdb/optimizer/late_materialization.hpp" #include "duckdb/optimizer/common_subplan_optimizer.hpp" #include "duckdb/optimizer/window_self_join.hpp" +#include "duckdb/optimizer/optimizer_extension.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/planner.hpp" @@ -325,7 +326,7 @@ unique_ptr Optimizer::Optimize(unique_ptr plan this->plan = std::move(plan_p); - for (auto &pre_optimizer_extension : DBConfig::GetConfig(context).optimizer_extensions) { + for (auto &pre_optimizer_extension : OptimizerExtension::Iterate(context)) { RunOptimizer(OptimizerType::EXTENSION, [&]() { OptimizerExtensionInput input {GetContext(), *this, pre_optimizer_extension.optimizer_info.get()}; if (pre_optimizer_extension.pre_optimize_function) { @@ -336,7 +337,7 @@ unique_ptr Optimizer::Optimize(unique_ptr plan RunBuiltInOptimizers(); - for (auto &optimizer_extension : DBConfig::GetConfig(context).optimizer_extensions) { + for (auto &optimizer_extension : OptimizerExtension::Iterate(context)) { RunOptimizer(OptimizerType::EXTENSION, [&]() { OptimizerExtensionInput input {GetContext(), *this, optimizer_extension.optimizer_info.get()}; if (optimizer_extension.optimize_function) { diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_get.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_get.cpp index ac4b6532a..3066c789d 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_get.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_get.cpp @@ -53,9 +53,10 @@ unique_ptr FilterPushdown::PushdownGet(unique_ptr(std::move(op)); } + auto &column_ids = get.GetColumnIds(); //! We generate the table filters that will be executed during the table scan vector pushdown_results; - get.table_filters = combiner.GenerateTableScanFilters(get.GetColumnIds(), pushdown_results); + get.table_filters = combiner.GenerateTableScanFilters(column_ids, pushdown_results); GenerateFilters(); @@ -73,8 +74,13 @@ unique_ptr FilterPushdown::PushdownGet(unique_ptrfilter; - if (expr.IsVolatile() || expr.CanThrow()) { - // we cannot push down volatile or throwing expressions + if (expr.IsVolatile()) { + continue; + } + // Allow pushing down filters that can throw only if there is a single expression + // For now, do not push down single expressions with IN either. Later we can change InClauseRewriter to handle + // this case + if (expr.CanThrow() && (expr.type == ExpressionType::COMPARE_IN || filters.size() > 1)) { continue; } pushdown_result = combiner.TryPushdownGenericExpression(get, expr); diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_outer_join.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_outer_join.cpp index 648c5e3d4..12958def3 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_outer_join.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_outer_join.cpp @@ -71,7 +71,7 @@ static unique_ptr ReplaceIn(unique_ptr expr, const expre } }); - return std::move(expr); + return expr; } //! True if replacing all the `args` expressions occurring in `expr` with a diff --git a/src/duckdb/src/optimizer/remove_duplicate_groups.cpp b/src/duckdb/src/optimizer/remove_duplicate_groups.cpp index dd09c2f3d..1ffd96942 100644 --- a/src/duckdb/src/optimizer/remove_duplicate_groups.cpp +++ b/src/duckdb/src/optimizer/remove_duplicate_groups.cpp @@ -23,6 +23,13 @@ void RemoveDuplicateGroups::VisitAggregate(LogicalAggregate &aggr) { return; } + // If there are multiple grouping sets (ROLLUP/CUBE), we cannot remove duplicate groups + // because the position of groups matters semantically in ROLLUP(col1, col2, col3), + // even if col1 and col3 reference the same column binding (e.g., after join column replacement) + if (aggr.grouping_sets.size() > 1) { + return; + } + auto &groups = aggr.groups; column_binding_map_t duplicate_map; diff --git a/src/duckdb/src/optimizer/remove_unused_columns.cpp b/src/duckdb/src/optimizer/remove_unused_columns.cpp index 7b0e49c6b..102ddb592 100644 --- a/src/duckdb/src/optimizer/remove_unused_columns.cpp +++ b/src/duckdb/src/optimizer/remove_unused_columns.cpp @@ -23,6 +23,7 @@ #include "duckdb/planner/operator/logical_set_operation.hpp" #include "duckdb/planner/operator/logical_simple.hpp" #include "duckdb/function/scalar/struct_utils.hpp" +#include "duckdb/function/scalar/variant_utils.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include @@ -76,6 +77,7 @@ void RemoveUnusedColumns::ClearUnusedExpressions(vector &list, idx_t table_id } if (!entry->second.child_columns.empty() && entry->second.supports_pushdown_extract == PushdownExtractSupport::ENABLED) { + //! One or more children of this column are referenced, and pushdown-extract is enabled should_replace = true; } if (should_replace) { @@ -93,14 +95,7 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: { // aggregate auto &aggr = op.Cast(); - // if there is more than one grouping set, the group by most likely has a rollup or cube - // If there is an equality join underneath the aggregate, this can change the groups to avoid unused columns - // This causes the duplicate eliminator to ignore functionality provided by grouping sets - bool new_root = false; - if (aggr.grouping_sets.size() > 1) { - new_root = true; - } - if (!everything_referenced && !new_root) { + if (!everything_referenced) { // FIXME: groups that are not referenced need to stay -> but they don't need to be scanned and output! ClearUnusedExpressions(aggr.expressions, aggr.aggregate_index); if (aggr.expressions.empty() && aggr.groups.empty()) { @@ -113,7 +108,10 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { } // then recurse into the children of the aggregate - RemoveUnusedColumns remove(binder, context, new_root); + // Note: We allow all optimizations (join column replacement, column pruning) to run below ROLLUP + // The duplicate groups optimizer will be responsible for not breaking ROLLUP by skipping when + // multiple grouping sets are present + RemoveUnusedColumns remove(binder, context, everything_referenced); remove.VisitOperatorExpressions(op); remove.VisitOperator(*op.children[0]); return; @@ -337,54 +335,64 @@ static idx_t GetColumnIdsIndexForFilter(vector &column_ids, idx_t f return static_cast(std::distance(column_ids.begin(), it)); } -static ColumnIndex PathToIndex(const vector &path, optional_ptr> cast_expression) { - D_ASSERT(!path.empty()); - ColumnIndex index = ColumnIndex(path[0]); - reference current(index); - for (idx_t i = 1; i < path.size(); i++) { - current.get().AddChildIndex(ColumnIndex(path[i])); - current = current.get().GetChildIndex(0); +//! returns: found_path, depth of the found path +std::pair FindShortestMatchingPath(column_index_set &all_paths, + const ColumnIndex &full_path) { + idx_t depth = 0; + column_index_set::iterator entry; + + ColumnIndex copy; + if (full_path.HasPrimaryIndex()) { + copy = ColumnIndex(full_path.GetPrimaryIndex()); + } else { + copy = ColumnIndex(full_path.GetFieldName()); } - if (cast_expression) { - auto &cast = *cast_expression; - current.get().SetType(cast->return_type); + + reference path_iter(full_path); + reference copy_iter(copy); + while (true) { + if (path_iter.get().HasType()) { + copy_iter.get().SetType(path_iter.get().GetType()); + } + entry = all_paths.find(copy); + if (entry != all_paths.end()) { + //! Path found, we're done + return make_pair(entry, depth); + } + if (!path_iter.get().HasChildren()) { + break; + } + path_iter = path_iter.get().GetChildIndex(0); + + ColumnIndex new_child; + if (path_iter.get().HasPrimaryIndex()) { + new_child = ColumnIndex(path_iter.get().GetPrimaryIndex()); + } else { + new_child = ColumnIndex(path_iter.get().GetFieldName()); + } + + copy_iter.get().AddChildIndex(new_child); + copy_iter = copy_iter.get().GetChildIndex(0); + depth++; } - return index; + return make_pair(all_paths.end(), depth); } void RemoveUnusedColumns::WritePushdownExtractColumns( const ColumnBinding &binding, ReferencedColumn &col, idx_t original_idx, const LogicalType &column_type, - const std::function cast_type)> &callback) { + const std::function cast_type)> &callback) { //! For each struct extract, replace the expression with a BoundColumnRefExpression //! The expression references a binding created for the extracted path, 1 per unique path for (auto &struct_extract : col.struct_extracts) { //! Replace the struct extract expression at the right depth with a BoundColumnRefExpression - auto &full_path = struct_extract.extract_path; - idx_t depth = 0; - column_index_set::iterator entry; - ColumnIndex copy(full_path.GetPrimaryIndex()); - reference path_iter(full_path); - reference copy_iter(copy); - while (true) { - if (path_iter.get().HasType()) { - copy_iter.get().SetType(path_iter.get().GetType()); - } - entry = col.unique_paths.find(copy); - if (entry != col.unique_paths.end()) { - //! Path found, we're done - break; - } - if (!path_iter.get().HasChildren()) { - throw InternalException("This path wasn't found in the registered paths for this expression at all!?"); - } - path_iter = path_iter.get().GetChildIndex(0); - copy_iter.get().AddChildIndex(ColumnIndex(path_iter.get().GetPrimaryIndex())); - copy_iter = copy_iter.get().GetChildIndex(0); - depth++; + auto res = FindShortestMatchingPath(col.unique_paths, full_path); + auto entry = res.first; + auto depth = res.second; + if (entry == col.unique_paths.end()) { + throw InternalException("This path wasn't found in the registered paths for this expression at all!?"); } - D_ASSERT(entry != col.unique_paths.end()); D_ASSERT(struct_extract.components.size() > depth); auto &component = struct_extract.components[depth]; auto &expr = component.cast ? *component.cast : component.extract; @@ -432,7 +440,7 @@ static unique_ptr ConstructStructExtractFromPath(ClientContext &cont } path_iter = path_iter.get().GetChildIndex(0); } - return std::move(target); + return target; } void RemoveUnusedColumns::RewriteExpressions(LogicalProjection &proj, idx_t expression_count) { @@ -461,7 +469,7 @@ void RemoveUnusedColumns::RewriteExpressions(LogicalProjection &proj, idx_t expr //! Pushdown Extract is supported, emit a column for every field WritePushdownExtractColumns( entry->first, entry->second, i, column_type, - [&](const ColumnIndex &extract_path, optional_ptr cast_type) -> idx_t { + [&](const ColumnIndex &extract_path, optional_ptr cast_type) -> idx_t { auto target = make_uniq(column_type, original_binding); target->SetAlias(expr.GetAlias()); auto new_extract = ConstructStructExtractFromPath(context, std::move(target), extract_path); @@ -469,7 +477,9 @@ void RemoveUnusedColumns::RewriteExpressions(LogicalProjection &proj, idx_t expr auto cast = BoundCastExpression::AddCastToType(context, std::move(new_extract), *cast_type); new_extract = std::move(cast); } - auto it = new_bindings.emplace(extract_path, expressions.size()).first; + ColumnIndex full_path(i); + full_path.AddChildIndex(extract_path); + auto it = new_bindings.emplace(full_path, expressions.size()).first; if (it->second == expressions.size()) { expressions.push_back(std::move(new_extract)); } @@ -645,23 +655,24 @@ void RemoveUnusedColumns::RemoveColumnsFromLogicalGet(LogicalGet &get) { auto struct_column_index = old_column_ids[col_sel_idx].GetPrimaryIndex(); //! Pushdown Extract is supported, emit a column for every field - WritePushdownExtractColumns(entry->first, entry->second, col_sel_idx, column_type, - [&](const ColumnIndex &extract_path, optional_ptr cast_type) -> idx_t { - ColumnIndex new_index(struct_column_index, {extract_path}); - new_index.SetPushdownExtractType(column_type, cast_type); - - auto column_binding_index = new_column_ids.size(); - auto entry = child_map.find(new_index); - if (entry == child_map.end()) { - //! Adds the binding for the child only if it doesn't exist yet - entry = child_map.emplace(new_index, column_binding_index).first; - created_bindings[new_index.GetPrimaryIndex()]++; - - new_column_ids.emplace_back(std::move(new_index)); - original_ids.emplace_back(col_sel_idx); - } - return entry->second; - }); + WritePushdownExtractColumns( + entry->first, entry->second, col_sel_idx, column_type, + [&](const ColumnIndex &extract_path, optional_ptr cast_type) -> idx_t { + ColumnIndex new_index(struct_column_index, {extract_path}); + new_index.SetPushdownExtractType(column_type, cast_type); + + auto column_binding_index = new_column_ids.size(); + auto entry = child_map.find(new_index); + if (entry == child_map.end()) { + //! Adds the binding for the child only if it doesn't exist yet + entry = child_map.emplace(new_index, column_binding_index).first; + created_bindings[new_index.GetPrimaryIndex()]++; + + new_column_ids.emplace_back(std::move(new_index)); + original_ids.emplace_back(col_sel_idx); + } + return entry->second; + }); } if (new_column_ids.empty()) { // this generally means we are only interested in whether or not anything exists in the table (e.g. @@ -710,64 +721,126 @@ BaseColumnPrunerMode BaseColumnPruner::GetMode() const { return mode; } -bool BaseColumnPruner::HandleStructExtractRecursive(unique_ptr &expr_p, - optional_ptr &colref, - vector &indexes, - vector &expressions) { - auto &expr = *expr_p; - if (expr.GetExpressionClass() != ExpressionClass::BOUND_FUNCTION) { - return false; - } - auto &function = expr.Cast(); - if (function.function.name != "struct_extract_at" && function.function.name != "struct_extract" && - function.function.name != "array_extract") { - return false; +bool BaseColumnPruner::HandleStructExtract(unique_ptr &expr_p, + optional_ptr &colref, + reference &path_ref, + vector &expressions) { + auto &function = expr_p->Cast(); + auto &child = function.children[0]; + D_ASSERT(child->return_type.id() == LogicalTypeId::STRUCT); + auto &bind_data = function.bind_info->Cast(); + // struct extract, check if left child is a bound column ref + if (child->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { + // column reference - check if it is a struct + auto &ref = child->Cast(); + if (ref.return_type.id() != LogicalTypeId::STRUCT) { + return false; + } + colref = &ref; + auto &path = path_ref.get(); + path.AddChildIndex(ColumnIndex(bind_data.index)); + path_ref = path.GetChildIndex(0); + expressions.emplace_back(expr_p); + return true; } - if (!function.bind_info) { + // not a column reference - try to handle this recursively + if (!HandleExtractRecursive(child, colref, path_ref, expressions)) { return false; } + auto &path = path_ref.get(); + path.AddChildIndex(ColumnIndex(bind_data.index)); + path_ref = path.GetChildIndex(0); + + expressions.emplace_back(expr_p); + return true; +} + +bool BaseColumnPruner::HandleVariantExtract(unique_ptr &expr_p, + optional_ptr &colref, + reference &path_ref, + vector &expressions) { + auto &function = expr_p->Cast(); auto &child = function.children[0]; - if (child->return_type.id() != LogicalTypeId::STRUCT) { + D_ASSERT(child->return_type.id() == LogicalTypeId::VARIANT); + auto &bind_data = function.bind_info->Cast(); + if (bind_data.component.lookup_mode != VariantChildLookupMode::BY_KEY) { + //! We don't push down variant extract on ARRAY values return false; } - auto &bind_data = function.bind_info->Cast(); - // struct extract, check if left child is a bound column ref + // variant extract, check if left child is a bound column ref if (child->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { - // column reference - check if it is a struct + // column reference - check if it is a variant auto &ref = child->Cast(); - if (ref.return_type.id() != LogicalTypeId::STRUCT) { + if (ref.return_type.id() != LogicalTypeId::VARIANT) { return false; } colref = &ref; - indexes.push_back(bind_data.index); + + auto &path = path_ref.get(); + path.AddChildIndex(ColumnIndex(bind_data.component.key)); + path_ref = path.GetChildIndex(0); + expressions.emplace_back(expr_p); return true; } // not a column reference - try to handle this recursively - if (!HandleStructExtractRecursive(child, colref, indexes, expressions)) { + if (!HandleExtractRecursive(child, colref, path_ref, expressions)) { return false; } - indexes.push_back(bind_data.index); + + auto &path = path_ref.get(); + path.AddChildIndex(ColumnIndex(bind_data.component.key)); + path_ref = path.GetChildIndex(0); + expressions.emplace_back(expr_p); return true; } -bool BaseColumnPruner::HandleStructExtract(unique_ptr *expression, - optional_ptr> cast_expression) { +bool BaseColumnPruner::HandleExtractRecursive(unique_ptr &expr_p, + optional_ptr &colref, + reference &path_ref, + vector &expressions) { + auto &expr = *expr_p; + if (expr.GetExpressionClass() != ExpressionClass::BOUND_FUNCTION) { + return false; + } + auto &function = expr.Cast(); + if (function.function.name != "struct_extract_at" && function.function.name != "struct_extract" && + function.function.name != "array_extract" && function.function.name != "variant_extract") { + return false; + } + if (!function.bind_info) { + return false; + } + auto &child = function.children[0]; + auto child_type = child->return_type.id(); + switch (child_type) { + case LogicalTypeId::STRUCT: + return HandleStructExtract(expr_p, colref, path_ref, expressions); + case LogicalTypeId::VARIANT: + return HandleVariantExtract(expr_p, colref, path_ref, expressions); + default: + return false; + } +} + +bool BaseColumnPruner::HandleExtractExpression(unique_ptr *expression, + optional_ptr> cast_expression) { optional_ptr colref; - vector indexes; vector expressions; - if (!HandleStructExtractRecursive(*expression, colref, indexes, expressions)) { + ColumnIndex path(0); + reference path_ref(path); + if (!HandleExtractRecursive(*expression, colref, path_ref, expressions)) { return false; } if (cast_expression) { auto &top_level = expressions.back(); top_level.cast = cast_expression; + path_ref.get().SetType((*cast_expression)->return_type); } - auto index = PathToIndex(indexes, cast_expression); - AddBinding(*colref, std::move(index), expressions); + AddBinding(*colref, path.GetChildIndex(0), expressions); return true; } @@ -779,8 +852,20 @@ void BaseColumnPruner::MergeChildColumns(vector ¤t_child_colu } // if we are already extract sub-fields, add it (if it is not there yet) for (auto &binding : current_child_columns) { - if (binding.GetPrimaryIndex() != new_child_column.GetPrimaryIndex()) { - continue; + if (binding.HasPrimaryIndex()) { + if (!new_child_column.HasPrimaryIndex()) { + continue; + } + if (binding.GetPrimaryIndex() != new_child_column.GetPrimaryIndex()) { + continue; + } + } else { + if (new_child_column.HasPrimaryIndex()) { + continue; + } + if (binding.GetFieldName() != new_child_column.GetFieldName()) { + continue; + } } // found a match: sub-field is already projected // check if we have child columns @@ -827,26 +912,13 @@ void ReferencedColumn::AddPath(const ColumnIndex &path) { } path.VerifySinglePath(); - //! Do not add the path if it is a child of an existing path - ColumnIndex copy(path.GetPrimaryIndex()); - reference path_iter(path); - reference copy_iter(copy); - while (true) { - if (path_iter.get().HasType()) { - copy_iter.get().SetType(path_iter.get().GetType()); - } - //! Create a subset of the path up to an increasing depth, so we can check if the parent path already exists - if (unique_paths.count(copy)) { - //! The parent path already exists, don't add the new path - return; - } - if (!path_iter.get().HasChildren()) { - break; - } - path_iter = path_iter.get().GetChildIndex(0); - copy_iter.get().AddChildIndex(ColumnIndex(path_iter.get().GetPrimaryIndex())); - copy_iter = copy_iter.get().GetChildIndex(0); + auto res = FindShortestMatchingPath(unique_paths, path); + auto entry = res.first; + if (entry != unique_paths.end()) { + //! The parent path already exists, don't add the new path + return; } + //! No parent path exists, but child paths could already be added, remove them if they exist auto it = unique_paths.begin(); for (; it != unique_paths.end();) { @@ -912,14 +984,14 @@ void BaseColumnPruner::VisitExpression(unique_ptr *expression) { //! Check if this is a struct extract wrapped in a cast optional_ptr> cast_child; if (TryGetCastChild(*expression, cast_child)) { - if (HandleStructExtract(cast_child.get(), expression)) { + if (HandleExtractExpression(cast_child.get(), expression)) { // already handled return; } } //! Check if this is a struct extract - if (HandleStructExtract(expression)) { + if (HandleExtractExpression(expression)) { // already handled return; } diff --git a/src/duckdb/src/optimizer/row_group_pruner.cpp b/src/duckdb/src/optimizer/row_group_pruner.cpp index 5d293bb52..7ac859b01 100644 --- a/src/duckdb/src/optimizer/row_group_pruner.cpp +++ b/src/duckdb/src/optimizer/row_group_pruner.cpp @@ -8,6 +8,7 @@ #include "duckdb/planner/operator/logical_order.hpp" #include "duckdb/storage/table/row_group_reorderer.hpp" #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" namespace duckdb { @@ -78,7 +79,10 @@ bool RowGroupPruner::TryOptimize(LogicalOperator &op) const { const auto &primary_order = logical_order->orders[0]; auto options = CreateRowGroupReordererOptions(row_limit, row_offset, primary_order, *logical_get, storage_index, logical_limit); - logical_get->function.set_scan_order(std::move(options), logical_get->bind_data.get()); + if (!options) { + return false; + } + logical_get->SetScanOrder(std::move(options)); return true; } @@ -163,8 +167,8 @@ RowGroupPruner::CreateRowGroupReordererOptions(const optional_idx row_limit, con auto &colref = primary_order.expression->Cast(); auto column_type = colref.return_type == LogicalType::VARCHAR ? OrderByColumnType::STRING : OrderByColumnType::NUMERIC; - auto order_type = primary_order.type == OrderType::ASCENDING ? RowGroupOrderType::ASC : RowGroupOrderType::DESC; - auto order_by = order_type == RowGroupOrderType::ASC ? OrderByStatistics::MIN : OrderByStatistics::MAX; + auto order_type = primary_order.type; + auto order_by = order_type == OrderType::ASCENDING ? OrderByStatistics::MIN : OrderByStatistics::MAX; optional_idx combined_limit = row_limit.IsValid() ? row_limit.GetIndex() + (row_offset.IsValid() ? row_offset.GetIndex() : 0) : optional_idx(); diff --git a/src/duckdb/src/optimizer/rule/timestamp_comparison.cpp b/src/duckdb/src/optimizer/rule/timestamp_comparison.cpp index 8b5a71dc8..2a0f67ebf 100644 --- a/src/duckdb/src/optimizer/rule/timestamp_comparison.cpp +++ b/src/duckdb/src/optimizer/rule/timestamp_comparison.cpp @@ -5,6 +5,7 @@ #include "duckdb/common/constants.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/expression/bound_conjunction_expression.hpp" #include "duckdb/planner/expression/bound_comparison_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" diff --git a/src/duckdb/src/optimizer/statistics/expression/propagate_cast.cpp b/src/duckdb/src/optimizer/statistics/expression/propagate_cast.cpp index 9709a1290..794d04171 100644 --- a/src/duckdb/src/optimizer/statistics/expression/propagate_cast.cpp +++ b/src/duckdb/src/optimizer/statistics/expression/propagate_cast.cpp @@ -1,10 +1,16 @@ #include "duckdb/optimizer/statistics_propagator.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/storage/statistics/struct_stats.hpp" +#include "duckdb/storage/statistics/variant_stats.hpp" namespace duckdb { static unique_ptr StatisticsOperationsNumericNumericCast(const BaseStatistics &input, const LogicalType &target) { + // Bail out if the stats are not numeric + if (input.GetStatsType() != StatisticsType::NUMERIC_STATS) { + return nullptr; + } if (!NumericStats::HasMinMax(input)) { return nullptr; } @@ -142,9 +148,37 @@ bool StatisticsPropagator::CanPropagateCast(const LogicalType &source, const Log return true; } +static unique_ptr StatisticsPropagateVariant(const BaseStatistics &input, const LogicalType &target) { + if (target.IsNested() || target.id() == LogicalTypeId::VARIANT) { + // only try this for non-nested + return nullptr; + } + if (!VariantStats::IsShredded(input)) { + // not shredded + return nullptr; + } + auto structured_type = VariantStats::GetShreddedStructuredType(input); + auto &shredded_stats = VariantStats::GetShreddedStats(input); + if (!VariantShreddedStats::IsFullyShredded(shredded_stats)) { + // this field might be partially shredded - skip stats propagation + return nullptr; + } + // extract the typed stats + auto &typed_stats = VariantStats::GetTypedStats(shredded_stats); + if (structured_type == target) { + // type matches - return stats directly + return typed_stats.ToUnique(); + } + // typed stats don't match - try to cast + return StatisticsPropagator::TryPropagateCast(typed_stats, structured_type, target); +} + unique_ptr StatisticsPropagator::TryPropagateCast(const BaseStatistics &stats, const LogicalType &source, const LogicalType &target) { + if (source.id() == LogicalTypeId::VARIANT) { + return StatisticsPropagateVariant(stats, target); + } if (!CanPropagateCast(source, target)) { return nullptr; } diff --git a/src/duckdb/src/optimizer/statistics/operator/propagate_get.cpp b/src/duckdb/src/optimizer/statistics/operator/propagate_get.cpp index 708221883..362830447 100644 --- a/src/duckdb/src/optimizer/statistics/operator/propagate_get.cpp +++ b/src/duckdb/src/optimizer/statistics/operator/propagate_get.cpp @@ -15,7 +15,7 @@ namespace duckdb { -static void GetColumnIndex(unique_ptr &expr, idx_t &index, string &alias) { +static void GetColumnIndex(const unique_ptr &expr, idx_t &index, string &alias) { if (expr->type == ExpressionType::BOUND_REF) { auto &bound_ref = expr->Cast(); index = bound_ref.index; @@ -59,7 +59,7 @@ FilterPropagateResult StatisticsPropagator::PropagateTableFilter(ColumnBinding s return filter.CheckStatistics(stats); } -void StatisticsPropagator::UpdateFilterStatistics(BaseStatistics &input, TableFilter &filter) { +void StatisticsPropagator::UpdateFilterStatistics(BaseStatistics &input, const TableFilter &filter) { // FIXME: update stats... switch (filter.filter_type) { case TableFilterType::CONJUNCTION_AND: { @@ -79,7 +79,7 @@ void StatisticsPropagator::UpdateFilterStatistics(BaseStatistics &input, TableFi } } -static bool IsConstantOrNullFilter(TableFilter &table_filter) { +static bool IsConstantOrNullFilter(const TableFilter &table_filter) { if (table_filter.filter_type != TableFilterType::EXPRESSION_FILTER) { return false; } @@ -91,7 +91,7 @@ static bool IsConstantOrNullFilter(TableFilter &table_filter) { return ConstantOrNull::IsConstantOrNull(func, Value::BOOLEAN(true)); } -static bool CanReplaceConstantOrNull(TableFilter &table_filter) { +static bool CanReplaceConstantOrNull(const TableFilter &table_filter) { if (!IsConstantOrNullFilter(table_filter)) { throw InternalException("CanReplaceConstantOrNull() called on unexepected Table Filter"); } diff --git a/src/duckdb/src/optimizer/topn_window_elimination.cpp b/src/duckdb/src/optimizer/topn_window_elimination.cpp index e0d9f3e19..be5f194ee 100644 --- a/src/duckdb/src/optimizer/topn_window_elimination.cpp +++ b/src/duckdb/src/optimizer/topn_window_elimination.cpp @@ -360,7 +360,7 @@ TopNWindowElimination::TryCreateUnnestOperator(unique_ptr op, if (params.limit <= 1) { // LIMIT 1 -> we do not need to unnest - return std::move(op); + return op; } // Create unnest expression for aggregate args @@ -420,10 +420,16 @@ TopNWindowElimination::CreateProjectionOperator(unique_ptr op, const auto op_column_bindings = op->GetColumnBindings(); vector> proj_exprs; - // Only project necessary group columns + // Only project necessary group columns, but in the same order as they appear in the aggregate operator. + // For that, we need the group_idxs ordered by value. + std::set ordered_group_projection_idxs; for (const auto &group_idx : group_idxs) { - proj_exprs.push_back( - make_uniq(op->types[group_idx.second], op_column_bindings[group_idx.second])); + ordered_group_projection_idxs.insert(group_idx.second); + } + + for (const idx_t group_projection_idx : ordered_group_projection_idxs) { + proj_exprs.push_back(make_uniq(op->types[group_projection_idx], + op_column_bindings[group_projection_idx])); } auto aggregate_column_ref = @@ -544,9 +550,15 @@ bool TopNWindowElimination::CanOptimize(LogicalOperator &op) { if (window.window_index != filter_col_idx) { return false; } + const auto &first_window_expr = window.expressions[0]->Cast(); + for (auto &partition : first_window_expr.partitions) { + if (partition->GetExpressionClass() != ExpressionClass::BOUND_COLUMN_REF) { + return false; + } + } if (window.expressions.size() != 1) { for (idx_t i = 1; i < window.expressions.size(); ++i) { - if (!window.expressions[i]->Equals(*window.expressions[0])) { + if (!window.expressions[i]->Equals(first_window_expr)) { return false; } } @@ -619,6 +631,10 @@ vector> TopNWindowElimination::GenerateAggregatePayload(c if (aggregate_args.size() == 1) { // If we only project the aggregate value itself, we do not need it as an arg VisitExpression(&window_expr.orders[0].expression); + if (column_references.size() != 1) { + column_references.clear(); + return aggregate_args; + } const auto aggregate_value_binding = column_references.begin()->first; column_references.clear(); @@ -746,19 +762,29 @@ bool TopNWindowElimination::CanUseLateMaterialization(const LogicalWindow &windo vector> &stack) { auto &window_expr = window.expressions[0]->Cast(); vector projections(window_expr.partitions.size() + args.size()); + auto extract_single_binding = [&](unique_ptr *expr, ColumnBinding &binding) { + VisitExpression(expr); + if (column_references.size() != 1) { + column_references.clear(); + return false; + } + binding = column_references.begin()->first; + column_references.clear(); + return true; + }; // Build a projection list for an LHS table scan to recreate the column order of an aggregate with struct packing for (idx_t i = 0; i < window_expr.partitions.size(); i++) { auto &partition = window_expr.partitions[i]; - VisitExpression(&partition); - projections[i] = column_references.begin()->first; - column_references.clear(); + if (!extract_single_binding(&partition, projections[i])) { + return false; + } } for (idx_t i = 0; i < args.size(); i++) { auto &arg = args[i]; - VisitExpression(&arg); - projections[window_expr.partitions.size() + i] = column_references.begin()->first; - column_references.clear(); + if (!extract_single_binding(&arg, projections[window_expr.partitions.size() + i])) { + return false; + } } reference op = *window.children[0]; @@ -770,11 +796,16 @@ bool TopNWindowElimination::CanUseLateMaterialization(const LogicalWindow &windo case LogicalOperatorType::LOGICAL_PROJECTION: { auto &projection = op.get().Cast(); for (idx_t i = 0; i < projections.size(); i++) { - D_ASSERT(projection.table_index == projections[i].table_index); + if (projection.table_index != projections[i].table_index) { + return false; + } const idx_t projection_idx = projections[i].column_index; - VisitExpression(&projection.expressions[projection_idx]); - projections[i] = column_references.begin()->first; - column_references.clear(); + if (projection_idx >= projection.expressions.size()) { + return false; + } + if (!extract_single_binding(&projection.expressions[projection_idx], projections[i])) { + return false; + } } op = *op.get().children[0]; break; @@ -797,12 +828,14 @@ bool TopNWindowElimination::CanUseLateMaterialization(const LogicalWindow &windo if (condition.comparison != ExpressionType::COMPARE_EQUAL) { return false; } - VisitExpression(&condition.left); - auto left_binding = column_references.begin()->first; - column_references.clear(); - VisitExpression(&condition.right); - auto right_binding = column_references.begin()->first; - column_references.clear(); + ColumnBinding left_binding; + if (!extract_single_binding(&condition.left, left_binding)) { + return false; + } + ColumnBinding right_binding; + if (!extract_single_binding(&condition.right, right_binding)) { + return false; + } replaceable_bindings[left_binding] = right_binding; replaceable_bindings[right_binding] = left_binding; @@ -822,6 +855,15 @@ bool TopNWindowElimination::CanUseLateMaterialization(const LogicalWindow &windo bool all_right_replaceable = true; for (idx_t i = 0; i < projections.size(); i++) { const auto &projection = projections[i]; + if (projection.table_index != left_idx && projection.table_index != right_idx) { + return false; + } + if (projection.table_index == left_idx && projection.column_index >= left_column_bindings.size()) { + return false; + } + if (projection.table_index == right_idx && projection.column_index >= right_column_bindings.size()) { + return false; + } auto &column_binding = projection.table_index == left_idx ? left_column_bindings[projection.column_index] : right_column_bindings[projection.column_index]; @@ -842,6 +884,17 @@ bool TopNWindowElimination::CanUseLateMaterialization(const LogicalWindow &windo idx_t replace_table_idx = all_right_replaceable ? right_idx : left_idx; for (idx_t i = 0; i < projections.size(); i++) { const auto projection_idx = projections[i]; + if (projection_idx.table_index != left_idx && projection_idx.table_index != right_idx) { + return false; + } + if (projection_idx.table_index == left_idx && + projection_idx.column_index >= left_column_bindings.size()) { + return false; + } + if (projection_idx.table_index == right_idx && + projection_idx.column_index >= right_column_bindings.size()) { + return false; + } auto &column_binding = projection_idx.table_index == left_idx ? left_column_bindings[projection_idx.column_index] : right_column_bindings[projection_idx.column_index]; @@ -864,7 +917,11 @@ bool TopNWindowElimination::CanUseLateMaterialization(const LogicalWindow &windo } stack.push_back(op); - D_ASSERT(op.get().type == LogicalOperatorType::LOGICAL_GET); + if (op.get().type != LogicalOperatorType::LOGICAL_GET) { + // Alternative verification can produce leaf operators without children that are not logical gets. + // In that case, late materialization is not applicable and we should gracefully fall back. + return false; + } auto &logical_get = op.get().Cast(); if (!logical_get.function.late_materialization || !logical_get.function.get_row_id_columns) { return false; @@ -991,9 +1048,12 @@ unique_ptr TopNWindowElimination::ConstructLHS(LogicalGet &rhs, vector> projs; projs.reserve(projections.size()); - for (auto projection_id : projections) { - projs.push_back(make_uniq(lhs_get->types[projection_id], - ColumnBinding {lhs_get->table_index, projection_id})); + const auto &column_ids = lhs_get->GetColumnIds(); + for (auto column_idx : projections) { + D_ASSERT(column_idx < column_ids.size()); + const auto &column_type = lhs_get->GetColumnType(column_ids[column_idx]); + projs.push_back( + make_uniq(column_type, ColumnBinding {lhs_get->table_index, column_idx})); } auto projection = make_uniq(optimizer.binder.GenerateTableIndex(), std::move(projs)); projection->children.push_back(std::move(lhs_get)); diff --git a/src/duckdb/src/optimizer/window_self_join.cpp b/src/duckdb/src/optimizer/window_self_join.cpp index a3879b27e..c0c8d2a51 100644 --- a/src/duckdb/src/optimizer/window_self_join.cpp +++ b/src/duckdb/src/optimizer/window_self_join.cpp @@ -4,6 +4,8 @@ #include "duckdb/planner/operator/logical_window.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" #include "duckdb/planner/operator/logical_aggregate.hpp" +#include "duckdb/planner/operator/logical_dummy_scan.hpp" +#include "duckdb/planner/operator/logical_expression_get.hpp" #include "duckdb/planner/operator/logical_projection.hpp" #include "duckdb/planner/expression/bound_window_expression.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" @@ -17,6 +19,24 @@ namespace duckdb { class WindowSelfJoinTableRebinder : public LogicalOperatorVisitor { public: + static bool CanRebind(const LogicalOperator &op) { + switch (op.type) { + case LogicalOperatorType::LOGICAL_GET: + case LogicalOperatorType::LOGICAL_EXPRESSION_GET: + case LogicalOperatorType::LOGICAL_PROJECTION: + case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: + case LogicalOperatorType::LOGICAL_DUMMY_SCAN: + case LogicalOperatorType::LOGICAL_FILTER: + if (!op.children.empty()) { + return CanRebind(*op.children[0]); + } + return true; + default: + break; + } + return false; + } + explicit WindowSelfJoinTableRebinder(Optimizer &optimizer) : optimizer(optimizer) { } @@ -46,6 +66,19 @@ class WindowSelfJoinTableRebinder : public LogicalOperatorVisitor { agg.aggregate_index = new_agg_idx; agg.group_index = new_grp_idx; } + if (op.type == LogicalOperatorType::LOGICAL_EXPRESSION_GET) { + auto &get = op.Cast(); + auto new_idx = optimizer.binder.GenerateTableIndex(); + table_map[get.table_index] = new_idx; + get.table_index = new_idx; + } + if (op.type == LogicalOperatorType::LOGICAL_DUMMY_SCAN) { + auto &dummy = op.Cast(); + auto new_idx = optimizer.binder.GenerateTableIndex(); + table_map[dummy.table_index] = new_idx; + dummy.table_index = new_idx; + } + // TODO: Handle other operators defining tables if needed // But Get/Projection/Aggregate are most common in subplans. @@ -63,6 +96,46 @@ class WindowSelfJoinTableRebinder : public LogicalOperatorVisitor { } VisitExpressionChildren(**expression); } + + unique_ptr TranslateAggregate(const BoundWindowExpression &w_expr) { + auto agg_func = *w_expr.aggregate; + unique_ptr bind_info; + if (w_expr.bind_info) { + bind_info = w_expr.bind_info->Copy(); + } else { + bind_info = nullptr; + } + + vector> children; + for (auto &child : w_expr.children) { + auto child_copy = child->Copy(); + VisitExpression(&child_copy); // Update bindings + children.push_back(std::move(child_copy)); + } + + unique_ptr filter; + if (w_expr.filter_expr) { + filter = w_expr.filter_expr->Copy(); + VisitExpression(&filter); // Update bindings + } + + auto aggr_type = w_expr.distinct ? AggregateType::DISTINCT : AggregateType::NON_DISTINCT; + + auto result = make_uniq(std::move(agg_func), std::move(children), std::move(filter), + std::move(bind_info), aggr_type); + + if (!w_expr.arg_orders.empty()) { + result->order_bys = make_uniq(); + auto &orders = result->order_bys->orders; + for (auto &order : w_expr.arg_orders) { + auto order_copy = order.Copy(); + VisitExpression(&order_copy.expression); // Update bindings + orders.emplace_back(std::move(order_copy)); + } + } + + return std::move(result); + } }; WindowSelfJoinOptimizer::WindowSelfJoinOptimizer(Optimizer &optimizer) : optimizer(optimizer) { @@ -77,6 +150,26 @@ unique_ptr WindowSelfJoinOptimizer::Optimize(unique_ptr WindowSelfJoinOptimizer::OptimizeInternal(unique_ptr op, ColumnBindingReplacer &replacer) { if (op->type == LogicalOperatorType::LOGICAL_WINDOW) { @@ -85,23 +178,18 @@ unique_ptr WindowSelfJoinOptimizer::OptimizeInternal(unique_ptr // Check recursively window.children[0] = OptimizeInternal(std::move(window.children[0]), replacer); - if (window.expressions.size() != 1) { - return op; - } - if (window.expressions[0]->type != ExpressionType::WINDOW_AGGREGATE) { + if (!WindowSelfJoinTableRebinder::CanRebind(*window.children[0])) { return op; } - auto &w_expr = window.expressions[0]->Cast(); - if (w_expr.aggregate->name != "count" && w_expr.aggregate->name != "count_star") { - return op; - } - if (!w_expr.orders.empty()) { - return op; - } - if (w_expr.partitions.empty()) { - return op; + auto &w_expr0 = window.expressions[0]->Cast(); + for (auto &expr : window.expressions) { + auto &w_expr = expr->Cast(); + if (!CanOptimize(w_expr, w_expr0)) { + return op; + } } + auto &partitions = w_expr0.partitions; // --- Transformation --- @@ -119,34 +207,17 @@ unique_ptr WindowSelfJoinOptimizer::OptimizeInternal(unique_ptr vector> aggregates; // Create Aggregate Operator - for (auto &part : w_expr.partitions) { + for (auto &part : partitions) { auto part_copy = part->Copy(); rebinder.VisitExpression(&part_copy); // Update bindings groups.push_back(std::move(part_copy)); } - auto count_func = *w_expr.aggregate; - unique_ptr bind_info; - if (w_expr.bind_info) { - bind_info = w_expr.bind_info->Copy(); - } else { - bind_info = nullptr; - } - - vector> children; - for (auto &child : w_expr.children) { - auto child_copy = child->Copy(); - rebinder.VisitExpression(&child_copy); // Update bindings - children.push_back(std::move(child_copy)); + for (auto &expr : window.expressions) { + auto &w_expr = expr->Cast(); + aggregates.emplace_back(rebinder.TranslateAggregate(w_expr)); } - auto aggr_type = w_expr.distinct ? AggregateType::DISTINCT : AggregateType::NON_DISTINCT; - - auto agg_expr = make_uniq(std::move(count_func), std::move(children), nullptr, - std::move(bind_info), aggr_type); - - aggregates.push_back(std::move(agg_expr)); - // args: group_index, aggregate_index, ... auto agg_op = make_uniq(group_index, aggregate_index, std::move(aggregates)); @@ -161,12 +232,11 @@ unique_ptr WindowSelfJoinOptimizer::OptimizeInternal(unique_ptr // Inner Join on the partition keys auto join = make_uniq(JoinType::INNER); - for (size_t i = 0; i < w_expr.partitions.size(); ++i) { + for (size_t i = 0; i < partitions.size(); ++i) { JoinCondition cond; cond.comparison = ExpressionType::COMPARE_NOT_DISTINCT_FROM; - cond.left = w_expr.partitions[i]->Copy(); - cond.right = - make_uniq(w_expr.partitions[i]->return_type, ColumnBinding(group_index, i)); + cond.left = partitions[i]->Copy(); + cond.right = make_uniq(partitions[i]->return_type, ColumnBinding(group_index, i)); join->conditions.push_back(std::move(cond)); } @@ -174,13 +244,14 @@ unique_ptr WindowSelfJoinOptimizer::OptimizeInternal(unique_ptr join->children.push_back(std::move(agg_op)); join->ResolveOperatorTypes(); - // Replace Count binding - // Old window column: (window.window_index, 0) - // New constant column: (aggregate_index, 0) - ColumnBinding old_binding(window.window_index, 0); - ColumnBinding new_binding(aggregate_index, 0); - - replacer.replacement_bindings.emplace_back(old_binding, new_binding); + // Replace aggregate bindings + // Old window column: (window.window_index, x) + // New constant column: (aggregate_index, x) + for (idx_t column_index = 0; column_index < window.expressions.size(); ++column_index) { + ColumnBinding old_binding(window.window_index, column_index); + ColumnBinding new_binding(aggregate_index, column_index); + replacer.replacement_bindings.emplace_back(old_binding, new_binding); + } return std::move(join); } else if (!op->children.empty()) { diff --git a/src/duckdb/src/parallel/executor.cpp b/src/duckdb/src/parallel/executor.cpp index 9a9cf4703..9ab72c3c7 100644 --- a/src/duckdb/src/parallel/executor.cpp +++ b/src/duckdb/src/parallel/executor.cpp @@ -8,6 +8,7 @@ #include "duckdb/execution/physical_operator.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/client_data.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/parallel/meta_pipeline.hpp" #include "duckdb/parallel/pipeline_complete_event.hpp" #include "duckdb/parallel/pipeline_event.hpp" @@ -593,7 +594,7 @@ PendingExecutionResult Executor::ExecuteTask(bool dry_run) { if (!HasError()) { // we (partially) processed a task and no exceptions were thrown // give back control to the caller - if (task && DBConfig::GetConfig(context).options.scheduler_process_partial) { + if (task && Settings::Get(context)) { auto &token = *task->token; TaskScheduler::GetScheduler(context).ScheduleTask(token, task); task.reset(); diff --git a/src/duckdb/src/parallel/pipeline.cpp b/src/duckdb/src/parallel/pipeline.cpp index 1e5a20b4a..d48cc1241 100644 --- a/src/duckdb/src/parallel/pipeline.cpp +++ b/src/duckdb/src/parallel/pipeline.cpp @@ -157,7 +157,7 @@ bool Pipeline::IsOrderDependent() const { return true; } } - if (!DBConfig::GetSetting(executor.context)) { + if (!Settings::Get(executor.context)) { return false; } if (sink && sink->SinkOrderDependent()) { @@ -255,6 +255,10 @@ void Pipeline::AddDependency(shared_ptr &pipeline) { pipeline->parents.push_back(weak_ptr(shared_from_this())); } +vector> Pipeline::GetDependencies() const { + return dependencies; +} + string Pipeline::ToString() const { TextTreeRenderer renderer; return renderer.ToString(*this); diff --git a/src/duckdb/src/parallel/pipeline_executor.cpp b/src/duckdb/src/parallel/pipeline_executor.cpp index 274dc8b99..7b1ad5424 100644 --- a/src/duckdb/src/parallel/pipeline_executor.cpp +++ b/src/duckdb/src/parallel/pipeline_executor.cpp @@ -262,8 +262,8 @@ PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { } if (result == OperatorResultType::FINISHED) { + D_ASSERT(in_process_operators.empty()); exhausted_pipeline = true; - break; } } while (chunk_budget.Next()); diff --git a/src/duckdb/src/parallel/task_scheduler.cpp b/src/duckdb/src/parallel/task_scheduler.cpp index b5ed2db24..43024474b 100644 --- a/src/duckdb/src/parallel/task_scheduler.cpp +++ b/src/duckdb/src/parallel/task_scheduler.cpp @@ -5,6 +5,7 @@ #include "duckdb/common/numeric_utils.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/database.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/storage/block_allocator.hpp" #ifndef DUCKDB_NO_THREADS #include "concurrentqueue.h" @@ -226,15 +227,15 @@ ProducerToken::~ProducerToken() { TaskScheduler::TaskScheduler(DatabaseInstance &db) : db(db), queue(make_uniq()), allocator_flush_threshold(db.config.options.allocator_flush_threshold), - allocator_background_threads(db.config.options.allocator_background_threads), requested_thread_count(0), + allocator_background_threads(Settings::Get(db)), requested_thread_count(0), current_thread_count(1) { - SetAllocatorBackgroundThreads(db.config.options.allocator_background_threads); + SetAllocatorBackgroundThreads(allocator_background_threads); } TaskScheduler::~TaskScheduler() { #ifndef DUCKDB_NO_THREADS try { - RelaunchThreadsInternal(0); + RelaunchThreadsInternal(0, true); } catch (...) { // nothing we can do in the destructor if this fails } @@ -299,8 +300,10 @@ void TaskScheduler::ExecuteForever(atomic *marker) { } } if (queue->Dequeue(task)) { - auto process_mode = config.options.scheduler_process_partial ? TaskExecutionMode::PROCESS_PARTIAL - : TaskExecutionMode::PROCESS_ALL; + auto process_mode = TaskExecutionMode::PROCESS_ALL; + if (Settings::Get(config)) { + process_mode = TaskExecutionMode::PROCESS_PARTIAL; + } auto execute_result = task->Execute(process_mode); switch (execute_result) { @@ -497,7 +500,7 @@ idx_t TaskScheduler::GetEstimatedCPUId() { void TaskScheduler::RelaunchThreads() { lock_guard t(thread_lock); auto n = requested_thread_count.load(); - RelaunchThreadsInternal(n); + RelaunchThreadsInternal(n, false); } #ifndef DUCKDB_NO_THREADS @@ -514,12 +517,21 @@ static void SetThreadAffinity(thread &thread, const int &cpu_id) { } #endif -void TaskScheduler::RelaunchThreadsInternal(int32_t n) { +void TaskScheduler::RelaunchThreadsInternal(int32_t n, bool destroy) { #ifndef DUCKDB_NO_THREADS auto &config = DBConfig::GetConfig(db); auto new_thread_count = NumericCast(n); + + idx_t external_threads = 0; + ThreadPinMode pin_thread_mode = ThreadPinMode::AUTO; + if (!destroy) { + // If we are destroying, i.e., calling ~TaskScheduler, we don't want to read the settings + external_threads = Settings::Get(config); + pin_thread_mode = Settings::Get(db); + } + if (threads.size() == new_thread_count) { - current_thread_count = NumericCast(threads.size() + config.options.external_threads); + current_thread_count = NumericCast(threads.size() + external_threads); return; } if (threads.size() > new_thread_count) { @@ -542,9 +554,9 @@ void TaskScheduler::RelaunchThreadsInternal(int32_t n) { // Whether to pin threads to cores static constexpr idx_t THREAD_PIN_THRESHOLD = 64; - const auto pin_threads = db.config.options.pin_threads == ThreadPinMode::ON || - (db.config.options.pin_threads == ThreadPinMode::AUTO && - std::thread::hardware_concurrency() > THREAD_PIN_THRESHOLD); + const auto pin_threads = + pin_thread_mode == ThreadPinMode::ON || + (pin_thread_mode == ThreadPinMode::AUTO && std::thread::hardware_concurrency() > THREAD_PIN_THRESHOLD); for (idx_t i = 0; i < create_new_threads; i++) { // launch a thread and assign it a cancellation marker auto marker = unique_ptr>(new atomic(true)); @@ -565,7 +577,7 @@ void TaskScheduler::RelaunchThreadsInternal(int32_t n) { markers.push_back(std::move(marker)); } } - current_thread_count = NumericCast(threads.size() + config.options.external_threads); + current_thread_count = NumericCast(threads.size() + external_threads); BlockAllocator::Get(db).FlushAll(); #endif } diff --git a/src/duckdb/src/parser/constraints/foreign_key_constraint.cpp b/src/duckdb/src/parser/constraints/foreign_key_constraint.cpp index db76fd516..d9384a3d1 100644 --- a/src/duckdb/src/parser/constraints/foreign_key_constraint.cpp +++ b/src/duckdb/src/parser/constraints/foreign_key_constraint.cpp @@ -24,7 +24,7 @@ string ForeignKeyConstraint::ToString() const { base += KeywordHelper::WriteOptionallyQuoted(fk_columns[i]); } base += ") REFERENCES "; - if (!info.schema.empty()) { + if (!info.schema.empty() && info.schema != DEFAULT_SCHEMA) { base += info.schema; base += "."; } diff --git a/src/duckdb/src/parser/expression/lambda_expression.cpp b/src/duckdb/src/parser/expression/lambda_expression.cpp index 2b14abd61..7e0a812a2 100644 --- a/src/duckdb/src/parser/expression/lambda_expression.cpp +++ b/src/duckdb/src/parser/expression/lambda_expression.cpp @@ -1,10 +1,10 @@ #include "duckdb/parser/expression/lambda_expression.hpp" +#include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/types/hash.hpp" +#include "duckdb/parser/expression/columnref_expression.hpp" #include "duckdb/parser/expression/function_expression.hpp" -#include "duckdb/common/serializer/serializer.hpp" - namespace duckdb { LambdaExpression::LambdaExpression() : ParsedExpression(ExpressionType::LAMBDA, ExpressionClass::LAMBDA) { diff --git a/src/duckdb/src/parser/expression/type_expression.cpp b/src/duckdb/src/parser/expression/type_expression.cpp new file mode 100644 index 000000000..c6822a96c --- /dev/null +++ b/src/duckdb/src/parser/expression/type_expression.cpp @@ -0,0 +1,137 @@ +#include "duckdb/parser/expression/type_expression.hpp" +#include "duckdb/common/exception.hpp" +#include "duckdb/common/types/value.hpp" +#include "duckdb/common/string_util.hpp" +#include "duckdb/parser/expression/constant_expression.hpp" +#include "duckdb/common/types/hash.hpp" +namespace duckdb { + +TypeExpression::TypeExpression(string catalog, string schema, string type_name, + vector> children_p) + : ParsedExpression(ExpressionType::TYPE, ExpressionClass::TYPE), catalog(std::move(catalog)), + schema(std::move(schema)), type_name(std::move(type_name)), children(std::move(children_p)) { + D_ASSERT(!this->type_name.empty()); +} + +TypeExpression::TypeExpression(string type_name, vector> children) + : TypeExpression(INVALID_CATALOG, INVALID_SCHEMA, std::move(type_name), std::move(children)) { +} + +TypeExpression::TypeExpression() : ParsedExpression(ExpressionType::TYPE, ExpressionClass::TYPE) { +} + +string TypeExpression::ToString() const { + string result; + if (!catalog.empty()) { + result += KeywordHelper::WriteOptionallyQuoted(catalog) + "."; + } + if (!schema.empty()) { + result += KeywordHelper::WriteOptionallyQuoted(schema) + "."; + } + + auto ¶ms = children; + + // LIST and ARRAY have special syntax + if (result.empty() && StringUtil::CIEquals(type_name, "LIST") && params.size() == 1) { + return params[0]->ToString() + "[]"; + } + if (result.empty() && StringUtil::CIEquals(type_name, "ARRAY") && params.size() == 2) { + auto &type_param = params[0]; + auto &size_param = params[1]; + return type_param->ToString() + "[" + size_param->ToString() + "]"; + } + // So does STRUCT, MAP and UNION + if (result.empty() && StringUtil::CIEquals(type_name, "STRUCT")) { + if (params.empty()) { + return "STRUCT"; + } + string struct_result = "STRUCT("; + for (idx_t i = 0; i < params.size(); i++) { + struct_result += KeywordHelper::WriteOptionallyQuoted(params[i]->GetAlias()) + " " + params[i]->ToString(); + if (i < params.size() - 1) { + struct_result += ", "; + } + } + struct_result += ")"; + return struct_result; + } + if (result.empty() && StringUtil::CIEquals(type_name, "UNION")) { + if (params.empty()) { + return "UNION"; + } + string union_result = "UNION("; + for (idx_t i = 0; i < params.size(); i++) { + union_result += KeywordHelper::WriteOptionallyQuoted(params[i]->GetAlias()) + " " + params[i]->ToString(); + if (i < params.size() - 1) { + union_result += ", "; + } + } + union_result += ")"; + return union_result; + } + + if (result.empty() && StringUtil::CIEquals(type_name, "MAP") && params.size() == 2) { + return "MAP(" + params[0]->ToString() + ", " + params[1]->ToString() + ")"; + } + + if (result.empty() && StringUtil::CIEquals(type_name, "VARCHAR") && !params.empty()) { + if (params.back()->HasAlias() && StringUtil::CIEquals(params.back()->GetAlias(), "collation")) { + // Special case for VARCHAR with collation + auto collate_expr = params.back()->Cast(); + return StringUtil::Format("VARCHAR COLLATE %s", SQLIdentifier(StringValue::Get(collate_expr.value))); + } + } + + if (result.empty() && StringUtil::CIEquals(type_name, "INTERVAL") && !params.empty()) { + // We ignore interval types parameters. + return "INTERVAL"; + } + + result += KeywordHelper::WriteOptionallyQuoted(type_name, '"', true, KeywordCategory::KEYWORD_COL_NAME); + + if (!params.empty()) { + result += "("; + for (idx_t i = 0; i < params.size(); i++) { + result += params[i]->ToString(); + if (i < params.size() - 1) { + result += ", "; + } + } + result += ")"; + } + return result; +} + +unique_ptr TypeExpression::Copy() const { + vector> copy_children; + copy_children.reserve(children.size()); + for (const auto &child : children) { + copy_children.push_back(child->Copy()); + } + + auto copy = make_uniq(catalog, schema, type_name, std::move(copy_children)); + copy->CopyProperties(*this); + + return std::move(copy); +} + +bool TypeExpression::Equal(const TypeExpression &a, const TypeExpression &b) { + if (a.catalog != b.catalog || a.schema != b.schema || a.type_name != b.type_name) { + return false; + } + return ParsedExpression::ListEquals(a.children, b.children); +} + +void TypeExpression::Verify() const { + D_ASSERT(!type_name.empty()); +} + +hash_t TypeExpression::Hash() const { + hash_t result = ParsedExpression::Hash(); + result = CombineHash(result, duckdb::Hash(catalog.c_str())); + result = CombineHash(result, duckdb::Hash(schema.c_str())); + result = CombineHash(result, duckdb::Hash(type_name.c_str())); + return result; +} + +} // namespace duckdb diff --git a/src/duckdb/src/parser/keyword_helper.cpp b/src/duckdb/src/parser/keyword_helper.cpp index 80cea773b..fd488170f 100644 --- a/src/duckdb/src/parser/keyword_helper.cpp +++ b/src/duckdb/src/parser/keyword_helper.cpp @@ -4,15 +4,15 @@ namespace duckdb { -bool KeywordHelper::IsKeyword(const string &text) { - return Parser::IsKeyword(text) != KeywordCategory::KEYWORD_NONE; +bool KeywordHelper::IsKeyword(const string &text, KeywordCategory category) { + return Parser::IsKeyword(text) != category; } KeywordCategory KeywordHelper::KeywordCategoryType(const string &text) { return Parser::IsKeyword(text); } -bool KeywordHelper::RequiresQuotes(const string &text, bool allow_caps) { +bool KeywordHelper::RequiresQuotes(const string &text, bool allow_caps, KeywordCategory category) { for (size_t i = 0; i < text.size(); i++) { if (i > 0 && (text[i] >= '0' && text[i] <= '9')) { continue; @@ -30,7 +30,7 @@ bool KeywordHelper::RequiresQuotes(const string &text, bool allow_caps) { } return true; } - return IsKeyword(text); + return IsKeyword(text, category); } string KeywordHelper::EscapeQuotes(const string &text, char quote) { @@ -43,8 +43,8 @@ string KeywordHelper::WriteQuoted(const string &text, char quote) { return string(1, quote) + EscapeQuotes(text, quote) + string(1, quote); } -string KeywordHelper::WriteOptionallyQuoted(const string &text, char quote, bool allow_caps) { - if (!RequiresQuotes(text, allow_caps)) { +string KeywordHelper::WriteOptionallyQuoted(const string &text, char quote, bool allow_caps, KeywordCategory category) { + if (!RequiresQuotes(text, allow_caps, category)) { return text; } return WriteQuoted(text, quote); diff --git a/src/duckdb/src/parser/parsed_data/alter_table_info.cpp b/src/duckdb/src/parser/parsed_data/alter_table_info.cpp index 8d50e3dd6..b0d3d8b27 100644 --- a/src/duckdb/src/parser/parsed_data/alter_table_info.cpp +++ b/src/duckdb/src/parser/parsed_data/alter_table_info.cpp @@ -671,4 +671,79 @@ string SetSortedByInfo::ToString() const { return result; } +//===--------------------------------------------------------------------===// +// SetTblPropertiesInfo +//===--------------------------------------------------------------------===// +SetTableOptionsInfo::SetTableOptionsInfo() : AlterTableInfo(AlterTableType::SET_TABLE_OPTIONS) { +} + +SetTableOptionsInfo::SetTableOptionsInfo(AlterEntryData data, + case_insensitive_map_t> table_options) + : AlterTableInfo(AlterTableType::SET_TABLE_OPTIONS, std::move(data)), table_options(std::move(table_options)) { +} + +SetTableOptionsInfo::~SetTableOptionsInfo() { +} + +unique_ptr SetTableOptionsInfo::Copy() const { + case_insensitive_map_t> table_options_copy; + for (auto &option : table_options) { + table_options_copy.emplace(option.first, option.second->Copy()); + } + return make_uniq(GetAlterEntryData(), std::move(table_options_copy)); +} + +string SetTableOptionsInfo::ToString() const { + string result = "ALTER TABLE "; + result += QualifierToString(catalog, schema, name); + result += " SET ("; + idx_t i = 0; + for (auto &entry : table_options) { + if (i > 0) { + result += ", "; + } + result += KeywordHelper::WriteQuoted(entry.first, '\'') + "=" + entry.second->ToString(); + i++; + } + result += ")"; + return result; +} + +//===--------------------------------------------------------------------===// +// SetTblPropertiesInfo +//===--------------------------------------------------------------------===// +ResetTableOptionsInfo::ResetTableOptionsInfo() : AlterTableInfo(AlterTableType::RESET_TABLE_OPTIONS) { +} + +ResetTableOptionsInfo::ResetTableOptionsInfo(AlterEntryData data, case_insensitive_set_t table_options) + : AlterTableInfo(AlterTableType::RESET_TABLE_OPTIONS, std::move(data)), table_options(std::move(table_options)) { +} + +ResetTableOptionsInfo::~ResetTableOptionsInfo() { +} + +unique_ptr ResetTableOptionsInfo::Copy() const { + case_insensitive_set_t table_options_copy; + for (auto &option : table_options) { + table_options_copy.emplace(option); + } + return make_uniq(GetAlterEntryData(), table_options_copy); +} + +string ResetTableOptionsInfo::ToString() const { + string result = "ALTER TABLE "; + result += QualifierToString(catalog, schema, name); + result += " RESET ("; + idx_t i = 0; + for (auto &entry : table_options) { + if (i > 0) { + result += ", "; + } + result += KeywordHelper::WriteQuoted(entry, '\''); + i++; + } + result += ")"; + return result; +} + } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/create_coordinate_system_info.cpp b/src/duckdb/src/parser/parsed_data/create_coordinate_system_info.cpp new file mode 100644 index 000000000..be48d88dd --- /dev/null +++ b/src/duckdb/src/parser/parsed_data/create_coordinate_system_info.cpp @@ -0,0 +1,19 @@ +#include "duckdb/parser/parsed_data/create_coordinate_system_info.hpp" + +namespace duckdb { + +CreateCoordinateSystemInfo::CreateCoordinateSystemInfo(string name_p, string authority, string code, string projjson, + string wkt2_2019) + : CreateInfo(CatalogType::COORDINATE_SYSTEM_ENTRY), name(std::move(name_p)), authority(std::move(authority)), + code(std::move(code)), projjson_definition(std::move(projjson)), wkt2_2019_definition(std::move(wkt2_2019)) { + internal = true; +} + +unique_ptr CreateCoordinateSystemInfo::Copy() const { + auto result = + make_uniq(name, authority, code, projjson_definition, wkt2_2019_definition); + CopyProperties(*result); + return std::move(result); +} + +} // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/create_secret_info.cpp b/src/duckdb/src/parser/parsed_data/create_secret_info.cpp index afa50cf60..01cb3287d 100644 --- a/src/duckdb/src/parser/parsed_data/create_secret_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_secret_info.cpp @@ -4,8 +4,9 @@ namespace duckdb { -CreateSecretInfo::CreateSecretInfo(OnCreateConflict on_conflict, SecretPersistType persist_type) - : CreateInfo(CatalogType::SECRET_ENTRY), on_conflict(on_conflict), persist_type(persist_type), options() { +CreateSecretInfo::CreateSecretInfo(OnCreateConflict on_conflict_p, SecretPersistType persist_type) + : CreateInfo(CatalogType::SECRET_ENTRY), persist_type(persist_type), options() { + on_conflict = on_conflict_p; } CreateSecretInfo::~CreateSecretInfo() { diff --git a/src/duckdb/src/parser/parsed_data/create_table_info.cpp b/src/duckdb/src/parser/parsed_data/create_table_info.cpp index 539f08ba6..d556a5418 100644 --- a/src/duckdb/src/parser/parsed_data/create_table_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_table_info.cpp @@ -23,21 +23,62 @@ unique_ptr CreateTableInfo::Copy() const { for (auto &constraint : constraints) { result->constraints.push_back(constraint->Copy()); } + for (auto &partition : partition_keys) { + result->partition_keys.push_back(partition->Copy()); + } + for (auto &order : sort_keys) { + result->sort_keys.push_back(order->Copy()); + } + for (auto &option : options) { + result->options.emplace(option.first, option.second->Copy()); + } if (query) { result->query = unique_ptr_cast(query->Copy()); } return std::move(result); } +string CreateTableInfo::ExtraOptionsToString() const { + string ret; + if (!partition_keys.empty()) { + ret += " PARTITIONED BY ("; + for (auto &partition : partition_keys) { + ret += partition->ToString() + ","; + } + ret.pop_back(); + ret += ")"; + } + if (!sort_keys.empty()) { + ret += " SORTED BY ("; + for (auto &order : sort_keys) { + ret += order->ToString() + ","; + } + ret.pop_back(); + ret += ")"; + } + if (!options.empty()) { + ret += " WITH ("; + for (auto &entry : options) { + ret += "'" + entry.first + "'=" + entry.second->ToString() + ","; + } + ret.pop_back(); + ret += ")"; + } + return ret; +} + string CreateTableInfo::ToString() const { string ret = GetCreatePrefix("TABLE"); ret += QualifierToString(temporary ? "" : catalog, schema, table); if (query != nullptr) { ret += TableCatalogEntry::ColumnNamesToSQL(columns); + ret += ExtraOptionsToString(); ret += " AS " + query->ToString(); } else { - ret += TableCatalogEntry::ColumnsToSQL(columns, constraints) + ";"; + ret += TableCatalogEntry::ColumnsToSQL(columns, constraints); + ret += ExtraOptionsToString(); + ret += ";"; } return ret; } diff --git a/src/duckdb/src/parser/parsed_data/create_type_info.cpp b/src/duckdb/src/parser/parsed_data/create_type_info.cpp index c48799402..95d9bee19 100644 --- a/src/duckdb/src/parser/parsed_data/create_type_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_type_info.cpp @@ -41,13 +41,6 @@ string CreateTypeInfo::ToString() const { // CREATE TYPE mood AS ENUM (SELECT 'happy') D_ASSERT(query); result += " AS ENUM (" + query->ToString() + ")"; - } else if (type.id() == LogicalTypeId::USER) { - result += " AS "; - auto extra_info = type.AuxInfo(); - D_ASSERT(extra_info); - D_ASSERT(extra_info->type == ExtraTypeInfoType::USER_TYPE_INFO); - auto &user_info = extra_info->Cast(); - result += QualifierToString(user_info.catalog, user_info.schema, user_info.user_type_name); } else { result += " AS "; result += type.ToString(); diff --git a/src/duckdb/src/parser/parsed_data/create_view_info.cpp b/src/duckdb/src/parser/parsed_data/create_view_info.cpp index c4fe3a624..c574cf572 100644 --- a/src/duckdb/src/parser/parsed_data/create_view_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_view_info.cpp @@ -39,7 +39,7 @@ unique_ptr CreateViewInfo::Copy() const { CopyProperties(*result); result->aliases = aliases; result->types = types; - result->column_comments = column_comments; + result->column_comments_map = column_comments_map; result->query = unique_ptr_cast(query->Copy()); return std::move(result); } @@ -63,10 +63,6 @@ unique_ptr CreateViewInfo::FromSelect(ClientContext &context, un D_ASSERT(!info->query); info->query = ParseSelect(info->sql); - - auto binder = Binder::CreateBinder(context); - binder->BindCreateViewInfo(*info); - return info; } @@ -99,4 +95,44 @@ unique_ptr CreateViewInfo::FromCreateView(ClientContext &context return result; } +vector CreateViewInfo::GetColumnCommentsList() const { + if (column_comments_map.empty()) { + return vector(); + } + if (names.empty()) { + throw InternalException( + "Attempting to serialize column comments using the legacy format, but view is not bound"); + } + vector result; + result.resize(names.size()); + for (auto &entry : column_comments_map) { + auto it = std::find(names.begin(), names.end(), entry.first); + if (it == names.end()) { + throw InternalException( + "While serializing comments for view \"%s\" - did not find column \"%s\" in list of names", view_name, + entry.first); + } + result[NumericCast(it - names.begin())] = entry.second; + } + return result; +} + +CreateViewInfo::CreateViewInfo(vector names_p, vector comments, + unordered_map column_comments_p) + : CreateInfo(CatalogType::VIEW_ENTRY, INVALID_SCHEMA), names(std::move(names_p)), + column_comments_map(std::move(column_comments_p)) { + if (comments.empty()) { + return; + } + if (!column_comments_map.empty()) { + throw SerializationException("Either column_comments or column_comments_map should be provided, not both"); + } + for (idx_t i = 0; i < comments.size(); i++) { + if (comments[i].IsNull()) { + continue; + } + column_comments_map[names[i]] = std::move(comments[i]); + } +} + } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_expression.cpp b/src/duckdb/src/parser/parsed_expression.cpp index 2732e760c..5d270b8ff 100644 --- a/src/duckdb/src/parser/parsed_expression.cpp +++ b/src/duckdb/src/parser/parsed_expression.cpp @@ -87,6 +87,8 @@ bool ParsedExpression::Equals(const BaseExpression &other) const { return SubqueryExpression::Equal(Cast(), other.Cast()); case ExpressionClass::WINDOW: return WindowExpression::Equal(Cast(), other.Cast()); + case ExpressionClass::TYPE: + return TypeExpression::Equal(Cast(), other.Cast()); default: throw SerializationException("Unsupported type for expression comparison!"); } diff --git a/src/duckdb/src/parser/parsed_expression_iterator.cpp b/src/duckdb/src/parser/parsed_expression_iterator.cpp index f5746f9f7..f654bcf90 100644 --- a/src/duckdb/src/parser/parsed_expression_iterator.cpp +++ b/src/duckdb/src/parser/parsed_expression_iterator.cpp @@ -84,6 +84,13 @@ void ParsedExpressionIterator::EnumerateChildren( } break; } + case ExpressionClass::TYPE: { + auto &type_expr = expr.Cast(); + for (auto &child : type_expr.GetChildren()) { + callback(child); + } + break; + } case ExpressionClass::LAMBDA: { auto &lambda_expr = expr.Cast(); callback(lambda_expr.lhs); diff --git a/src/duckdb/src/parser/parser.cpp b/src/duckdb/src/parser/parser.cpp index 36b977c6a..b4f5544cc 100644 --- a/src/duckdb/src/parser/parser.cpp +++ b/src/duckdb/src/parser/parser.cpp @@ -1,5 +1,6 @@ #include "duckdb/parser/parser.hpp" +#include "duckdb/main/extension_callback_manager.hpp" #include "duckdb/parser/group_by_node.hpp" #include "duckdb/parser/parsed_data/create_table_info.hpp" #include "duckdb/parser/parser_extension.hpp" @@ -11,6 +12,7 @@ #include "duckdb/parser/tableref/expressionlistref.hpp" #include "duckdb/parser/transformer.hpp" #include "parser/parser.hpp" + #include "postgres_parser.hpp" namespace duckdb { @@ -218,8 +220,7 @@ void Parser::ThrowParserOverrideError(ParserOverrideResult &result) { result.error.RawMessage()); } if (result.error.Type() == ExceptionType::PARSER) { - throw ParserException("Parser override could not parse this query.\nOriginal error: %s", - result.error.RawMessage()); + result.error.Throw(); } result.error.Throw(); } @@ -229,7 +230,6 @@ void Parser::ParseQuery(const string &query) { Transformer transformer(options); string parser_error; optional_idx parser_error_location; - string parser_override_option = StringUtil::Lower(options.parser_override_setting); { // check if there are any unicode spaces in the string string new_query; @@ -241,56 +241,53 @@ void Parser::ParseQuery(const string &query) { } { if (options.extensions) { - for (auto &ext : *options.extensions) { + for (auto &ext : options.extensions->ParserExtensions()) { if (!ext.parser_override) { continue; } - if (StringUtil::CIEquals(parser_override_option, "default")) { + if (options.parser_override_setting == AllowParserOverride::DEFAULT_OVERRIDE) { continue; } - auto result = ext.parser_override(ext.parser_info.get(), query); + + auto result = ext.parser_override(ext.parser_info.get(), query, options); if (result.type == ParserExtensionResultType::PARSE_SUCCESSFUL) { statements = std::move(result.statements); return; } - if (StringUtil::CIEquals(parser_override_option, "strict")) { + if (options.parser_override_setting == AllowParserOverride::STRICT_OVERRIDE) { ThrowParserOverrideError(result); } - if (StringUtil::CIEquals(parser_override_option, "strict_when_supported")) { + if (options.parser_override_setting == AllowParserOverride::STRICT_WHEN_SUPPORTED) { auto statement = GetStatement(query); if (!statement) { break; } bool is_supported = false; switch (statement->type) { + case StatementType::ANALYZE_STATEMENT: + case StatementType::VACUUM_STATEMENT: case StatementType::CALL_STATEMENT: + case StatementType::MERGE_INTO_STATEMENT: case StatementType::TRANSACTION_STATEMENT: case StatementType::VARIABLE_SET_STATEMENT: case StatementType::LOAD_STATEMENT: + case StatementType::EXPLAIN_STATEMENT: + case StatementType::PREPARE_STATEMENT: case StatementType::ATTACH_STATEMENT: + case StatementType::SELECT_STATEMENT: case StatementType::DETACH_STATEMENT: case StatementType::DELETE_STATEMENT: case StatementType::DROP_STATEMENT: case StatementType::ALTER_STATEMENT: case StatementType::PRAGMA_STATEMENT: + case StatementType::INSERT_STATEMENT: + case StatementType::UPDATE_STATEMENT: case StatementType::COPY_DATABASE_STATEMENT: + case StatementType::CREATE_STATEMENT: + case StatementType::COPY_STATEMENT: + case StatementType::SET_STATEMENT: { is_supported = true; break; - case StatementType::CREATE_STATEMENT: { - auto &create_statement = statement->Cast(); - switch (create_statement.info->type) { - case CatalogType::INDEX_ENTRY: - case CatalogType::MACRO_ENTRY: - case CatalogType::SCHEMA_ENTRY: - case CatalogType::SECRET_ENTRY: - case CatalogType::SEQUENCE_ENTRY: - case CatalogType::TYPE_ENTRY: - is_supported = true; - break; - default: - is_supported = false; - } - break; } default: is_supported = false; @@ -299,7 +296,7 @@ void Parser::ParseQuery(const string &query) { if (is_supported) { ThrowParserOverrideError(result); } - } else if (StringUtil::CIEquals(parser_override_option, "fallback")) { + } else if (options.parser_override_setting == AllowParserOverride::FALLBACK_OVERRIDE) { continue; } } @@ -334,7 +331,7 @@ void Parser::ParseQuery(const string &query) { // no-op // return here would require refactoring into another function. o.w. will just no-op in order to run wrap up // code at the end of this function - } else if (!options.extensions || options.extensions->empty()) { + } else if (!options.extensions || !options.extensions->HasParserExtensions()) { throw ParserException::SyntaxError(query, parser_error, parser_error_location); } else { // split sql string into statements and re-parse using extension @@ -370,7 +367,7 @@ void Parser::ParseQuery(const string &query) { // LCOV_EXCL_START // let extensions parse the statement which DuckDB failed to parse bool parsed_single_statement = false; - for (auto &ext : *options.extensions) { + for (auto &ext : options.extensions->ParserExtensions()) { D_ASSERT(!parsed_single_statement); if (!ext.parse_function) { continue; diff --git a/src/duckdb/src/parser/query_node/set_operation_node.cpp b/src/duckdb/src/parser/query_node/set_operation_node.cpp index 30d36defc..9ab492ed5 100644 --- a/src/duckdb/src/parser/query_node/set_operation_node.cpp +++ b/src/duckdb/src/parser/query_node/set_operation_node.cpp @@ -127,7 +127,7 @@ unique_ptr SetOperationNode::SerializeChildNode(Serializer &serialize } bool SetOperationNode::SerializeChildList(Serializer &serializer) const { - return serializer.ShouldSerialize(6); + return serializer.ShouldSerialize(7); } } // namespace duckdb diff --git a/src/duckdb/src/parser/statement/update_statement.cpp b/src/duckdb/src/parser/statement/update_statement.cpp index 115e76d7f..4a8681f6a 100644 --- a/src/duckdb/src/parser/statement/update_statement.cpp +++ b/src/duckdb/src/parser/statement/update_statement.cpp @@ -33,7 +33,8 @@ unique_ptr UpdateSetInfo::Copy() const { return unique_ptr(new UpdateSetInfo(*this)); } -UpdateStatement::UpdateStatement() : SQLStatement(StatementType::UPDATE_STATEMENT) { +UpdateStatement::UpdateStatement() + : SQLStatement(StatementType::UPDATE_STATEMENT), prioritize_table_when_binding(false) { } UpdateStatement::UpdateStatement(const UpdateStatement &other) @@ -45,6 +46,7 @@ UpdateStatement::UpdateStatement(const UpdateStatement &other) returning_list.emplace_back(expr->Copy()); } cte_map = other.cte_map.Copy(); + prioritize_table_when_binding = other.prioritize_table_when_binding; } string UpdateStatement::ToString() const { diff --git a/src/duckdb/src/parser/tableref/pivotref.cpp b/src/duckdb/src/parser/tableref/pivotref.cpp index 8874fdee7..ffcc0ad38 100644 --- a/src/duckdb/src/parser/tableref/pivotref.cpp +++ b/src/duckdb/src/parser/tableref/pivotref.cpp @@ -2,6 +2,15 @@ #include "duckdb/parser/expression_util.hpp" #include "duckdb/common/limits.hpp" +#include "duckdb/common/exception/conversion_exception.hpp" +#include "duckdb/parser/expression/cast_expression.hpp" +#include "duckdb/parser/expression/constant_expression.hpp" +#include "duckdb/parser/expression/function_expression.hpp" +#include "duckdb/parser/expression/columnref_expression.hpp" +#include "duckdb/common/serializer/serializer.hpp" +#include "duckdb/common/serializer/deserializer.hpp" +#include "duckdb/common/types/value.hpp" + namespace duckdb { //===--------------------------------------------------------------------===// @@ -129,6 +138,169 @@ PivotColumnEntry PivotColumnEntry::Copy() const { return result; } +static bool TryFoldConstantForBackwardsCompatability(const ParsedExpression &expr, Value &value) { + switch (expr.GetExpressionType()) { + case ExpressionType::FUNCTION: { + auto &function = expr.Cast(); + if (function.function_name == "struct_pack") { + unordered_set unique_names; + child_list_t values; + values.reserve(function.children.size()); + for (const auto &child : function.children) { + if (!unique_names.insert(child->GetAlias()).second) { + return false; + } + Value child_value; + if (!TryFoldConstantForBackwardsCompatability(*child, child_value)) { + return false; + } + values.emplace_back(child->GetAlias(), std::move(child_value)); + } + value = Value::STRUCT(std::move(values)); + return true; + } else if (function.function_name == "list_value") { + vector values; + values.reserve(function.children.size()); + for (const auto &child : function.children) { + Value child_value; + if (!TryFoldConstantForBackwardsCompatability(*child, child_value)) { + return false; + } + values.emplace_back(std::move(child_value)); + } + + // figure out child type + LogicalType child_type(LogicalTypeId::SQLNULL); + for (auto &child_value : values) { + child_type = LogicalType::ForceMaxLogicalType(child_type, child_value.type()); + } + + // finally create the list + value = Value::LIST(child_type, values); + return true; + } else if (function.function_name == "map") { + Value keys; + if (!TryFoldConstantForBackwardsCompatability(*function.children[0], keys)) { + return false; + } + + Value values; + if (!TryFoldConstantForBackwardsCompatability(*function.children[1], values)) { + return false; + } + + vector keys_unpacked = ListValue::GetChildren(keys); + vector values_unpacked = ListValue::GetChildren(values); + + value = Value::MAP(ListType::GetChildType(keys.type()), ListType::GetChildType(values.type()), + keys_unpacked, values_unpacked); + return true; + } else { + return false; + } + } + case ExpressionType::VALUE_CONSTANT: { + auto &constant = expr.Cast(); + value = constant.value; + return true; + } + case ExpressionType::OPERATOR_CAST: { + auto &cast = expr.Cast(); + Value dummy_value; + if (!TryFoldConstantForBackwardsCompatability(*cast.child, dummy_value)) { + return false; + } + + // Try to default bind cast + LogicalType cast_type; + try { + cast_type = UnboundType::TryDefaultBind(cast.cast_type); + } catch (...) { + return false; + } + + if (cast_type == LogicalType::INVALID || cast_type == LogicalTypeId::UNBOUND) { + return false; + } + + string error_message; + if (!dummy_value.DefaultTryCastAs(cast_type, value, &error_message)) { + return false; + } + return true; + } + default: + return false; + } +} + +static bool TryFoldForBackwardsCompatibility(const unique_ptr &expr, vector &values) { + if (!expr) { + return true; + } + + switch (expr->GetExpressionType()) { + case ExpressionType::COLUMN_REF: { + auto &colref = expr->Cast(); + if (colref.IsQualified()) { + return false; + } + values.emplace_back(colref.GetColumnName()); + return true; + } + case ExpressionType::FUNCTION: { + auto &function = expr->Cast(); + if (function.function_name != "row") { + return false; + } + for (auto &child : function.children) { + if (!TryFoldForBackwardsCompatibility(child, values)) { + return false; + } + } + return true; + } + default: { + Value val; + if (!TryFoldConstantForBackwardsCompatability(*expr, val)) { + return false; + } + values.push_back(std::move(val)); + return true; + } + } +} + +void PivotColumnEntry::Serialize(Serializer &serializer) const { + if (serializer.ShouldSerialize(7) || !expr) { + serializer.WritePropertyWithDefault>(100, "values", values); + serializer.WritePropertyWithDefault>(101, "star_expr", expr); + serializer.WritePropertyWithDefault(102, "alias", alias); + } else { + // We used to only support constant values in pivot entries, and folded expressions in the + // transformer. So we need to seriaize in a backwards compatible way here by trying to fold + // the expression back to constant values. + vector dummy_values; + if (!TryFoldForBackwardsCompatibility(expr, dummy_values)) { + throw SerializationException( + "Cannot serialize arbitrary expression pivot entries when targeting database storage version '%s'", + serializer.GetOptions().serialization_compatibility.duckdb_version); + ; + } + serializer.WritePropertyWithDefault>(100, "values", dummy_values); + serializer.WritePropertyWithDefault>(101, "star_expr", nullptr); + serializer.WritePropertyWithDefault(102, "alias", alias); + } +} + +PivotColumnEntry PivotColumnEntry::Deserialize(Deserializer &deserializer) { + PivotColumnEntry result; + deserializer.ReadPropertyWithDefault>(100, "values", result.values); + deserializer.ReadPropertyWithDefault>(101, "star_expr", result.expr); + deserializer.ReadPropertyWithDefault(102, "alias", result.alias); + return result; +} + //===--------------------------------------------------------------------===// // PivotRef //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp b/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp index 256a10200..cc0643130 100644 --- a/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp +++ b/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp @@ -10,7 +10,9 @@ static void ParseSchemaTableNameFK(duckdb_libpgquery::PGRangeVar &input, Foreign if (input.catalogname) { throw ParserException("FOREIGN KEY constraints cannot be defined cross-database"); } - fk_info.schema = input.schemaname ? input.schemaname : ""; + if (input.schemaname) { + fk_info.schema = input.schemaname; + } fk_info.table = input.relname; } @@ -124,13 +126,19 @@ unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGCon case duckdb_libpgquery::PG_CONSTR_DEFAULT: column.SetDefaultValue(TransformExpression(constraint.raw_expr)); return nullptr; - case duckdb_libpgquery::PG_CONSTR_COMPRESSION: - column.SetCompressionType(CompressionTypeFromString(constraint.compression_name)); - if (column.CompressionType() == CompressionType::COMPRESSION_AUTO) { - throw ParserException("Unrecognized option for column compression, expected none, uncompressed, rle, " - "dictionary, pfor, bitpacking, fsst, chimp, patas, zstd, alp, alprd or roaring"); + case duckdb_libpgquery::PG_CONSTR_COMPRESSION: { + auto compression_type = EnumUtil::FromString(constraint.compression_name); + switch (compression_type) { + case CompressionType::COMPRESSION_AUTO: + case CompressionType::COMPRESSION_CONSTANT: + case CompressionType::COMPRESSION_EMPTY: + throw InvalidInputException("Compression method %d cannot be forced", constraint.compression_name); + default: + break; } + column.SetCompressionType(compression_type); return nullptr; + } case duckdb_libpgquery::PG_CONSTR_FOREIGN: return TransformForeignKeyConstraint(constraint, &column.Name()); default: diff --git a/src/duckdb/src/parser/transform/expression/transform_constant.cpp b/src/duckdb/src/parser/transform/expression/transform_constant.cpp index 88fd295ff..2f83a843c 100644 --- a/src/duckdb/src/parser/transform/expression/transform_constant.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_constant.cpp @@ -95,90 +95,4 @@ unique_ptr Transformer::TransformConstant(duckdb_libpgquery::P return std::move(constant); } -bool Transformer::ConstructConstantFromExpression(const ParsedExpression &expr, Value &value) { - // We have to construct it like this because we don't have the ClientContext for binding/executing the expr here - switch (expr.GetExpressionType()) { - case ExpressionType::FUNCTION: { - auto &function = expr.Cast(); - if (function.function_name == "struct_pack") { - unordered_set unique_names; - child_list_t values; - values.reserve(function.children.size()); - for (const auto &child : function.children) { - if (!unique_names.insert(child->GetAlias()).second) { - throw BinderException("Duplicate struct entry name \"%s\"", child->GetAlias()); - } - Value child_value; - if (!ConstructConstantFromExpression(*child, child_value)) { - return false; - } - values.emplace_back(child->GetAlias(), std::move(child_value)); - } - value = Value::STRUCT(std::move(values)); - return true; - } else if (function.function_name == "list_value") { - vector values; - values.reserve(function.children.size()); - for (const auto &child : function.children) { - Value child_value; - if (!ConstructConstantFromExpression(*child, child_value)) { - return false; - } - values.emplace_back(std::move(child_value)); - } - - // figure out child type - LogicalType child_type(LogicalTypeId::SQLNULL); - for (auto &child_value : values) { - child_type = LogicalType::ForceMaxLogicalType(child_type, child_value.type()); - } - - // finally create the list - value = Value::LIST(child_type, values); - return true; - } else if (function.function_name == "map") { - Value keys; - if (!ConstructConstantFromExpression(*function.children[0], keys)) { - return false; - } - - Value values; - if (!ConstructConstantFromExpression(*function.children[1], values)) { - return false; - } - - vector keys_unpacked = ListValue::GetChildren(keys); - vector values_unpacked = ListValue::GetChildren(values); - - value = Value::MAP(ListType::GetChildType(keys.type()), ListType::GetChildType(values.type()), - keys_unpacked, values_unpacked); - return true; - } else { - return false; - } - } - case ExpressionType::VALUE_CONSTANT: { - auto &constant = expr.Cast(); - value = constant.value; - return true; - } - case ExpressionType::OPERATOR_CAST: { - auto &cast = expr.Cast(); - Value dummy_value; - if (!ConstructConstantFromExpression(*cast.child, dummy_value)) { - return false; - } - - string error_message; - if (!dummy_value.DefaultTryCastAs(cast.cast_type, value, &error_message)) { - throw ConversionException("Unable to cast %s to %s", dummy_value.ToString(), - EnumUtil::ToString(cast.cast_type.id())); - } - return true; - } - default: - return false; - } -} - } // namespace duckdb diff --git a/src/duckdb/src/parser/transform/expression/transform_expression.cpp b/src/duckdb/src/parser/transform/expression/transform_expression.cpp index 73b42c9dd..0ab5a1f02 100644 --- a/src/duckdb/src/parser/transform/expression/transform_expression.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_expression.cpp @@ -1,5 +1,6 @@ #include "duckdb/common/exception.hpp" #include "duckdb/parser/expression/default_expression.hpp" +#include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/transformer.hpp" namespace duckdb { @@ -77,6 +78,8 @@ unique_ptr Transformer::TransformExpression(duckdb_libpgquery: return TransformBooleanTest(PGCast(node)); case duckdb_libpgquery::T_PGMultiAssignRef: return TransformMultiAssignRef(PGCast(node)); + case duckdb_libpgquery::T_PGString: + return TransformValue(PGCast(node)); default: throw NotImplementedException("Expression type %s (%d)", NodetypeToString(node.type), (int)node.type); } diff --git a/src/duckdb/src/parser/transform/expression/transform_subquery.cpp b/src/duckdb/src/parser/transform/expression/transform_subquery.cpp index 986e46e25..c5cd07025 100644 --- a/src/duckdb/src/parser/transform/expression/transform_subquery.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_subquery.cpp @@ -20,20 +20,20 @@ void RemoveOrderQualificationRecursive(unique_ptr &root_expr) unique_ptr Transformer::TransformSubquery(duckdb_libpgquery::PGSubLink &root) { auto subquery_expr = make_uniq(); - - subquery_expr->subquery = TransformSelectStmt(*root.subselect); SetQueryLocation(*subquery_expr, root.location); - D_ASSERT(subquery_expr->subquery); switch (root.subLinkType) { case duckdb_libpgquery::PG_EXISTS_SUBLINK: { subquery_expr->subquery_type = SubqueryType::EXISTS; + subquery_expr->subquery = TransformSelectStmt(*root.subselect); + D_ASSERT(subquery_expr->subquery); break; } case duckdb_libpgquery::PG_ANY_SUBLINK: case duckdb_libpgquery::PG_ALL_SUBLINK: { // comparison with ANY() or ALL() subquery_expr->subquery_type = SubqueryType::ANY; + // transform the test expression first to preserve positional parameter order subquery_expr->child = TransformExpression(root.testexpr); // get the operator name if (!root.operName) { @@ -52,6 +52,8 @@ unique_ptr Transformer::TransformSubquery(duckdb_libpgquery::P subquery_expr->comparison_type != ExpressionType::COMPARE_LESSTHANOREQUALTO) { throw ParserException("ANY and ALL operators require one of =,<>,>,<,>=,<= comparisons!"); } + subquery_expr->subquery = TransformSelectStmt(*root.subselect); + D_ASSERT(subquery_expr->subquery); if (root.subLinkType == duckdb_libpgquery::PG_ALL_SUBLINK) { // ALL sublink is equivalent to NOT(ANY) with inverted comparison // e.g. [= ALL()] is equivalent to [NOT(<> ANY())] @@ -65,6 +67,8 @@ unique_ptr Transformer::TransformSubquery(duckdb_libpgquery::P // return a single scalar value from the subquery // no child expression to compare to subquery_expr->subquery_type = SubqueryType::SCALAR; + subquery_expr->subquery = TransformSelectStmt(*root.subselect); + D_ASSERT(subquery_expr->subquery); break; } case duckdb_libpgquery::PG_ARRAY_SUBLINK: { @@ -73,6 +77,9 @@ unique_ptr Transformer::TransformSubquery(duckdb_libpgquery::P // "SELECT CASE WHEN ARRAY_AGG(col) IS NULL THEN [] ELSE ARRAY_AGG(col) END FROM (...) tbl" auto select_node = make_uniq(); + subquery_expr->subquery = TransformSelectStmt(*root.subselect); + D_ASSERT(subquery_expr->subquery); + unique_ptr array_agg_child; optional_ptr sub_select; if (subquery_expr->subquery->node->type == QueryNodeType::SELECT_NODE) { diff --git a/src/duckdb/src/parser/transform/helpers/transform_typename.cpp b/src/duckdb/src/parser/transform/helpers/transform_typename.cpp index 917b6cc80..b2492b176 100644 --- a/src/duckdb/src/parser/transform/helpers/transform_typename.cpp +++ b/src/duckdb/src/parser/transform/helpers/transform_typename.cpp @@ -6,315 +6,168 @@ #include "duckdb/common/types/decimal.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/parser/expression/constant_expression.hpp" +#include "duckdb/parser/expression/type_expression.hpp" namespace duckdb { -struct SizeModifiers { - int64_t width = 0; - int64_t scale = 0; - // How many modifiers were found - idx_t count = 0; -}; +unique_ptr Transformer::TransformTypeExpressionInternal(duckdb_libpgquery::PGTypeName &type_name) { + // Parse typename/any qualifications -static SizeModifiers GetSizeModifiers(duckdb_libpgquery::PGTypeName &type_name, LogicalTypeId base_type) { - SizeModifiers result; + string unbound_name; + string schema_name; + string catalog_name; - if (base_type == LogicalTypeId::DECIMAL) { - // Defaults for DECIMAL - result.width = 18; - result.scale = 3; + if (type_name.names->length == 0) { + throw ParserException("Type name cannot be empty"); } + if (type_name.names->length == 1) { + auto unbound_name_cell = type_name.names->head; - if (type_name.typmods) { - for (auto node = type_name.typmods->head; node; node = node->next) { - auto &const_val = *Transformer::PGPointerCast(node->data.ptr_value); - if (const_val.type != duckdb_libpgquery::T_PGAConst || - const_val.val.type != duckdb_libpgquery::T_PGInteger) { - throw ParserException("Expected an integer constant as type modifier"); - } - if (const_val.val.val.ival < 0) { - throw ParserException("Negative modifier not supported"); - } - if (result.count == 0) { - result.width = const_val.val.val.ival; - if (base_type == LogicalTypeId::BIT && const_val.location != -1) { - result.width = 0; - } - } else if (result.count == 1) { - result.scale = const_val.val.val.ival; - } else { - throw ParserException("A maximum of two modifiers is supported"); - } - result.count++; - } - } - return result; -} - -vector Transformer::TransformTypeModifiers(duckdb_libpgquery::PGTypeName &type_name) { - vector type_mods; - if (type_name.typmods) { - for (auto node = type_name.typmods->head; node; node = node->next) { - const auto &const_val = *PGPointerCast(node->data.ptr_value); - if (const_val.type != duckdb_libpgquery::T_PGAConst) { - throw ParserException("Expected a constant as type modifier"); - } - const auto const_expr = TransformValue(const_val.val); - type_mods.push_back(std::move(const_expr->value)); - } - if (type_mods.size() > 9) { - const auto name = PGPointerCast(type_name.names->tail->data.ptr_value)->val.str; - throw ParserException("'%s': a maximum of 9 type modifiers is allowed", name); - } - } - return type_mods; -} - -LogicalType Transformer::TransformTypeNameInternal(duckdb_libpgquery::PGTypeName &type_name) { - if (type_name.names->length > 1) { - // qualified typename - vector names; - for (auto cell = type_name.names->head; cell; cell = cell->next) { - names.push_back(PGPointerCast(cell->data.ptr_value)->val.str); - } - vector type_mods = TransformTypeModifiers(type_name); - switch (type_name.names->length) { - case 2: { - return LogicalType::USER(INVALID_CATALOG, std::move(names[0]), std::move(names[1]), std::move(type_mods)); - } - case 3: { - return LogicalType::USER(std::move(names[0]), std::move(names[1]), std::move(names[2]), - std::move(type_mods)); - } - default: - throw ParserException( - "Too many qualifications for type name - expected [catalog.schema.name] or [schema.name]"); - } + unbound_name = PGPointerCast(unbound_name_cell->data.ptr_value)->val.str; } + if (type_name.names->length == 2) { + auto schema_name_cell = type_name.names->head; + auto unbound_name_cell = schema_name_cell->next; - auto name = PGPointerCast(type_name.names->tail->data.ptr_value)->val.str; - // transform it to the SQL type - LogicalTypeId base_type = TransformStringToLogicalTypeId(name); - - if (base_type == LogicalTypeId::LIST) { - throw ParserException("LIST is not valid as a stand-alone type"); + schema_name = PGPointerCast(schema_name_cell->data.ptr_value)->val.str; + unbound_name = PGPointerCast(unbound_name_cell->data.ptr_value)->val.str; } - if (base_type == LogicalTypeId::ENUM) { - if (!type_name.typmods || type_name.typmods->length == 0) { - throw ParserException("Enum needs a set of entries"); - } - Vector enum_vector(LogicalType::VARCHAR, NumericCast(type_name.typmods->length)); - auto string_data = FlatVector::GetData(enum_vector); - idx_t pos = 0; - for (auto node = type_name.typmods->head; node; node = node->next) { - auto constant_value = PGPointerCast(node->data.ptr_value); - if (constant_value->type != duckdb_libpgquery::T_PGAConst || - constant_value->val.type != duckdb_libpgquery::T_PGString) { - throw ParserException("Enum type requires a set of strings as type modifiers"); - } - string_data[pos++] = StringVector::AddString(enum_vector, constant_value->val.val.str); - } - return LogicalType::ENUM(enum_vector, NumericCast(type_name.typmods->length)); + if (type_name.names->length == 3) { + auto catalog_name_cell = type_name.names->head; + auto schema_name_cell = catalog_name_cell->next; + auto unbound_name_cell = schema_name_cell->next; + + catalog_name = PGPointerCast(catalog_name_cell->data.ptr_value)->val.str; + schema_name = PGPointerCast(schema_name_cell->data.ptr_value)->val.str; + unbound_name = PGPointerCast(unbound_name_cell->data.ptr_value)->val.str; } - if (base_type == LogicalTypeId::GEOMETRY) { - if (!type_name.typmods || type_name.typmods->length == 0) { - return LogicalType::GEOMETRY(); - } - // Expect a single type modifier with the CRS definition - if (type_name.typmods->length != 1) { - throw ParserException( - "GEOMETRY type takes a single optional type modifier with a coordinate system definition"); - } - auto crs_node = PGPointerCast(type_name.typmods->head->data.ptr_value); - if (crs_node->type != duckdb_libpgquery::T_PGAConst || crs_node->val.type != duckdb_libpgquery::T_PGString) { - throw ParserException( - "GEOMETRY type modifier must be a string with a coordinate system definition definition"); - } - return LogicalType::GEOMETRY(crs_node->val.val.str); + if (type_name.names->length >= 4) { + throw ParserException( + "Too many qualifications for type name - expected [catalog.schema.name] or [schema.name]"); } - if (base_type == LogicalTypeId::STRUCT) { - if (!type_name.typmods || type_name.typmods->length == 0) { - throw ParserException("Struct needs a name and entries"); - } - child_list_t children; - case_insensitive_set_t name_collision_set; + D_ASSERT(!unbound_name.empty()); - for (auto node = type_name.typmods->head; node; node = node->next) { - auto &type_val = *PGPointerCast(node->data.ptr_value); - if (type_val.length != 2) { - throw ParserException("Struct entry needs an entry name and a type name"); - } + // The postgres parser emits a bunch of strange type names - we want to normalize them here so that the alias for + // columns from expressions containing these types actually use the DuckDB type name. + // Eventually we should make the parser emit the correct names directly. + auto known_type_id = TransformStringToLogicalTypeId(unbound_name); + if (known_type_id != LogicalTypeId::UNBOUND) { + unbound_name = LogicalTypeIdToString(known_type_id); + } - auto entry_name_node = PGPointerCast(type_val.head->data.ptr_value); - D_ASSERT(entry_name_node->type == duckdb_libpgquery::T_PGString); - auto entry_type_node = PGPointerCast(type_val.tail->data.ptr_value); - D_ASSERT(entry_type_node->type == duckdb_libpgquery::T_PGTypeName); + // Parse type modifiers + vector> type_params; + for (auto typemod = type_name.typmods ? type_name.typmods->head : nullptr; typemod; typemod = typemod->next) { + // Type mods are always a list of (name, node) pairs - auto entry_name = string(entry_name_node->val.str); - D_ASSERT(!entry_name.empty()); + string name_str; + auto typemod_node = PGPointerCast(typemod->data.ptr_value); - if (name_collision_set.find(entry_name) != name_collision_set.end()) { - throw ParserException("Duplicate struct entry name \"%s\"", entry_name); + if (typemod_node->type == duckdb_libpgquery::T_PGList) { + auto &typemod_pair = *PGPointerCast(typemod->data.ptr_value); + if (typemod_pair.length != 2) { + throw ParserException("Expected type modifier to be a pair of (name, value)"); } - name_collision_set.insert(entry_name); - auto entry_type = TransformTypeName(*entry_type_node); - children.push_back(make_pair(entry_name, entry_type)); - } - D_ASSERT(!children.empty()); - return LogicalType::STRUCT(children); - } - if (base_type == LogicalTypeId::VARIANT) { - return LogicalType::VARIANT(); - } - if (base_type == LogicalTypeId::MAP) { - if (!type_name.typmods || type_name.typmods->length != 2) { - throw ParserException("Map type needs exactly two entries, key and value type"); - } - auto key_type = - TransformTypeName(*PGPointerCast(type_name.typmods->head->data.ptr_value)); - auto value_type = - TransformTypeName(*PGPointerCast(type_name.typmods->tail->data.ptr_value)); - - return LogicalType::MAP(std::move(key_type), std::move(value_type)); - } - if (base_type == LogicalTypeId::UNION) { - if (!type_name.typmods || type_name.typmods->length == 0) { - throw ParserException("Union type needs at least one member"); - } - if (type_name.typmods->length > (int)UnionType::MAX_UNION_MEMBERS) { - throw ParserException("Union types can have at most %d members", UnionType::MAX_UNION_MEMBERS); - } + // This is the actual argument node + typemod_node = PGPointerCast(typemod_pair.tail->data.ptr_value); - child_list_t children; - case_insensitive_set_t name_collision_set; - - for (auto node = type_name.typmods->head; node; node = node->next) { - auto &type_val = *PGPointerCast(node->data.ptr_value); - if (type_val.length != 2) { - throw ParserException("Union type member needs a tag name and a type name"); + // Extract name of the type modifier (optional) + auto name_node = PGPointerCast(typemod_pair.head->data.ptr_value); + if (name_node) { + if (name_node->type != duckdb_libpgquery::T_PGString) { + throw ParserException("Expected a constant as type modifier name"); + } + name_str = PGPointerCast(name_node.get())->val.str; } + } - auto entry_name_node = PGPointerCast(type_val.head->data.ptr_value); - D_ASSERT(entry_name_node->type == duckdb_libpgquery::T_PGString); - auto entry_type_node = PGPointerCast(type_val.tail->data.ptr_value); - D_ASSERT(entry_type_node->type == duckdb_libpgquery::T_PGTypeName); + // Extract value of the type modifier + // This is either: + // 1. A constant value + // 2. A expression + // 3. A type name - auto entry_name = string(entry_name_node->val.str); - D_ASSERT(!entry_name.empty()); + if (typemod_node->type == duckdb_libpgquery::T_PGTypeName) { + auto type_node = *PGPointerCast(typemod_node.get()); + auto type_expr = TransformTypeExpression(type_node); + type_expr->SetAlias(std::move(name_str)); + type_params.push_back(std::move(type_expr)); + } else { + // Expression + auto expr = TransformExpression(*typemod_node); - if (name_collision_set.find(entry_name) != name_collision_set.end()) { - throw ParserException("Duplicate union type tag name \"%s\"", entry_name); + // TODO: Allow arbitrary expressions in the future + if (expr->GetExpressionClass() != ExpressionClass::CONSTANT) { + throw ParserException("Expected a constant as type modifier"); } - name_collision_set.insert(entry_name); - - auto entry_type = TransformTypeName(*entry_type_node); - children.push_back(make_pair(entry_name, entry_type)); + expr->SetAlias(std::move(name_str)); + type_params.push_back(std::move(expr)); } - D_ASSERT(!children.empty()); - return LogicalType::UNION(std::move(children)); - } - if (base_type == LogicalTypeId::USER) { - string user_type_name {name}; - vector type_mods = TransformTypeModifiers(type_name); - return LogicalType::USER(user_type_name, type_mods); } - SizeModifiers modifiers = GetSizeModifiers(type_name, base_type); - switch (base_type) { - case LogicalTypeId::VARCHAR: - if (modifiers.count > 1) { - throw ParserException("VARCHAR only supports a single modifier"); - } - // FIXME: create CHECK constraint based on varchar width - modifiers.width = 0; - return LogicalType::VARCHAR; - case LogicalTypeId::DECIMAL: - if (modifiers.count > 2) { - throw ParserException("DECIMAL only supports a maximum of two modifiers"); - } - if (modifiers.count == 1) { - // only width is provided: set scale to 0 - modifiers.scale = 0; - } - if (modifiers.width <= 0 || modifiers.width > Decimal::MAX_WIDTH_DECIMAL) { - throw ParserException("Width must be between 1 and %d!", (int)Decimal::MAX_WIDTH_DECIMAL); - } - if (modifiers.scale > modifiers.width) { - throw ParserException("Scale cannot be bigger than width"); - } - return LogicalType::DECIMAL(NumericCast(modifiers.width), NumericCast(modifiers.scale)); - case LogicalTypeId::INTERVAL: - if (modifiers.count > 1) { - throw ParserException("INTERVAL only supports a single modifier"); - } - modifiers.width = 0; - return LogicalType::INTERVAL; - case LogicalTypeId::BIT: - if (!modifiers.width && type_name.typmods) { - throw ParserException("Type %s does not support any modifiers!", LogicalType(base_type).ToString()); - } - return LogicalType(base_type); - case LogicalTypeId::TIMESTAMP: - if (modifiers.count == 0) { - return LogicalType::TIMESTAMP; - } - if (modifiers.count > 1) { - throw ParserException("TIMESTAMP only supports a single modifier"); - } - if (modifiers.width > 10) { - throw ParserException("TIMESTAMP only supports until nano-second precision (9)"); - } - if (modifiers.width == 0) { - return LogicalType::TIMESTAMP_S; - } - if (modifiers.width <= 3) { - return LogicalType::TIMESTAMP_MS; - } - if (modifiers.width <= 6) { - return LogicalType::TIMESTAMP; - } - return LogicalType::TIMESTAMP_NS; - default: - if (modifiers.count > 0) { - throw ParserException("Type %s does not support any modifiers!", LogicalType(base_type).ToString()); - } - return LogicalType(base_type); + auto result = make_uniq(catalog_name, schema_name, unbound_name, std::move(type_params)); + + // Assign query location + if (type_name.location >= 0) { + result->query_location = NumericCast(type_name.location); } + + return std::move(result); } -LogicalType Transformer::TransformTypeName(duckdb_libpgquery::PGTypeName &type_name) { +unique_ptr Transformer::TransformTypeExpression(duckdb_libpgquery::PGTypeName &type_name) { if (type_name.type != duckdb_libpgquery::T_PGTypeName) { throw ParserException("Expected a type"); } auto stack_checker = StackCheck(); - auto result_type = TransformTypeNameInternal(type_name); + + auto result = TransformTypeExpressionInternal(type_name); + if (type_name.arrayBounds) { - // array bounds: turn the type into a list + // For both arrays and lists, the inner type is stored as the first type parameter + idx_t extra_stack = 0; for (auto cell = type_name.arrayBounds->head; cell != nullptr; cell = cell->next) { StackCheck(extra_stack++); - auto val = PGPointerCast(cell->data.ptr_value); - if (val->type != duckdb_libpgquery::T_PGInteger) { - throw ParserException("Expected integer value as array bound"); - } - auto array_size = val->val.ival; - if (array_size < 0) { - // -1 if bounds are empty - result_type = LogicalType::LIST(result_type); - } else if (array_size == 0) { - // Empty arrays are not supported - throw ParserException("Arrays must have a size of at least 1"); - } else if (array_size > static_cast(ArrayType::MAX_ARRAY_SIZE)) { - throw ParserException("Arrays must have a size of at most %d", ArrayType::MAX_ARRAY_SIZE); - } else { - result_type = LogicalType::ARRAY(result_type, NumericCast(array_size)); + auto arg = PGPointerCast(cell->data.ptr_value); + + if (arg->type == duckdb_libpgquery::T_PGInteger) { + auto int_node = PGPointerCast(arg.get()); + auto size = int_node->val.ival; + + vector> type_params; + type_params.push_back(std::move(result)); + + if (size == -1) { + // LIST type + result = make_uniq("list", std::move(type_params)); + } else { + // ARRAY type + type_params.push_back(make_uniq(Value::BIGINT(int_node->val.ival))); + result = make_uniq("array", std::move(type_params)); + } + + continue; } + + throw ParserException("ARRAY bounds must only contain expressions"); } } - return result_type; + + // Assign query location + if (type_name.location >= 0) { + result->query_location = NumericCast(type_name.location); + } + + return result; +} + +LogicalType Transformer::TransformTypeName(duckdb_libpgquery::PGTypeName &type_name) { + auto type_expr = TransformTypeExpression(type_name); + return LogicalType::UNBOUND(std::move(type_expr)); } } // namespace duckdb diff --git a/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp b/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp index 203d90fdc..37800dfe0 100644 --- a/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp @@ -9,6 +9,8 @@ #include "duckdb/parser/statement/multi_statement.hpp" #include "duckdb/parser/statement/update_statement.hpp" #include "duckdb/parser/tableref/basetableref.hpp" +#include "duckdb/parser/expression/function_expression.hpp" +#include "duckdb/parser/statement/set_statement.hpp" namespace duckdb { @@ -31,12 +33,15 @@ void AddToMultiStatement(const unique_ptr &multi_statement, uniq } void AddUpdateToMultiStatement(const unique_ptr &multi_statement, const string &column_name, - const string &table_name, const unique_ptr &original_expression) { + const AlterEntryData &table_data, + const unique_ptr &original_expression) { auto update_statement = make_uniq(); + update_statement->prioritize_table_when_binding = true; auto table_ref = make_uniq(); - - table_ref->table_name = table_name; + table_ref->catalog_name = table_data.catalog; + table_ref->schema_name = table_data.schema; + table_ref->table_name = table_data.name; update_statement->table = std::move(table_ref); auto set_info = make_uniq(); @@ -55,25 +60,27 @@ unique_ptr TransformAndMaterializeAlter(const duckdb_libpgquery: auto multi_statement = make_uniq(); /* Here we do a workaround that consists of the following statements: * 1. `ALTER TABLE t ADD COLUMN col DEFAULT NULL;` - * 2. `UPDATE t SET u = ;` - * 3. `ALTER TABLE t ALTER u SET DEFAULT ;` + * 2. `UPDATE t SET col = ;` + * 3. `ALTER TABLE t ALTER col SET DEFAULT ;` + * * This workaround exists because, when statements like this were executed: * `ALTER TABLE ... ADD COLUMN ... DEFAULT ` * the WAL replay would re-run the default expression, and with expressions such as RANDOM or CURRENT_TIMESTAMP, the - * value would be different from that of the original run. By now doing an UPDATE, we force materialization of these - * values, which makes WAL replays consistent. + * value would be different from that of the original run. By now doing an UPDATE in statement 2, we force + * materialization of these values for all existing rows, which makes WAL replays consistent. */ // 1. `ALTER TABLE t ADD COLUMN col DEFAULT NULL;` AddToMultiStatement(multi_statement, std::move(info_with_null_placeholder)); // 2. `UPDATE t SET u = ;` - AddUpdateToMultiStatement(multi_statement, column_name, stmt.relation->relname, expression); + AddUpdateToMultiStatement(multi_statement, column_name, data, expression); // 3. `ALTER TABLE t ALTER u SET DEFAULT ;` // Reinstate the original default expression. AddToMultiStatement(multi_statement, make_uniq(data, column_name, std::move(expression))); + return multi_statement; } @@ -223,6 +230,29 @@ unique_ptr Transformer::TransformAlter(duckdb_libpgquery::PGAlterT result->info = make_uniq(std::move(data), std::move(orders)); break; } + case duckdb_libpgquery::PG_AT_SetRelOptions: { + case_insensitive_map_t> options; + if (command->options) { + TransformTableOptions(options, command->options); + } + result->info = make_uniq(std::move(data), std::move(options)); + break; + } + case duckdb_libpgquery::PG_AT_ResetRelOptions: { + case_insensitive_map_t> rel_options_map; + case_insensitive_set_t options; + if (command->options) { + // TransformTableOptions will throw if key values are parsed + TransformTableOptions(rel_options_map, command->options, true); + // make sure RESET only supports single value options + // default of true is allowed + for (auto &option : rel_options_map) { + options.insert(option.first); + } + } + result->info = make_uniq(std::move(data), std::move(options)); + break; + } default: throw NotImplementedException("No support for that ALTER TABLE option yet!"); } diff --git a/src/duckdb/src/parser/transform/statement/transform_comment_on.cpp b/src/duckdb/src/parser/transform/statement/transform_comment_on.cpp index 6ab5d9e68..d9680168d 100644 --- a/src/duckdb/src/parser/transform/statement/transform_comment_on.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_comment_on.cpp @@ -1,8 +1,9 @@ +#include "duckdb/parser/expression/columnref_expression.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/parsed_data/alter_info.hpp" #include "duckdb/parser/parsed_data/alter_table_info.hpp" -#include "duckdb/parser/statement/alter_statement.hpp" #include "duckdb/parser/parsed_data/comment_on_column_info.hpp" +#include "duckdb/parser/statement/alter_statement.hpp" #include "duckdb/parser/transformer.hpp" namespace duckdb { diff --git a/src/duckdb/src/parser/transform/statement/transform_create_function.cpp b/src/duckdb/src/parser/transform/statement/transform_create_function.cpp index 1525f634d..2632243af 100644 --- a/src/duckdb/src/parser/transform/statement/transform_create_function.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_create_function.cpp @@ -39,12 +39,6 @@ unique_ptr Transformer::TransformMacroFunction(duckdb_libpgquery: // Transform parameter default value if (param.defaultValue) { auto default_expr = TransformExpression(PGPointerCast(param.defaultValue)); - Value default_value; - if (!ConstructConstantFromExpression(*default_expr, default_value)) { - throw ParserException("Invalid default value for parameter '%s': %s", param.name, - default_expr->ToString()); - } - default_expr = make_uniq(std::move(default_value)); default_expr->SetAlias(param.name); macro_func->default_parameters[param.name] = std::move(default_expr); } else if (!macro_func->default_parameters.empty()) { diff --git a/src/duckdb/src/parser/transform/statement/transform_create_index.cpp b/src/duckdb/src/parser/transform/statement/transform_create_index.cpp index 3b13d53ce..47ce484dc 100644 --- a/src/duckdb/src/parser/transform/statement/transform_create_index.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_create_index.cpp @@ -66,7 +66,12 @@ unique_ptr Transformer::TransformCreateIndex(duckdb_libpgquery: auto def_elem = PGPointerCast(cell->data.ptr_value); Value val; if (def_elem->arg) { - val = TransformValue(*PGPointerCast(def_elem->arg))->value; + auto expr = TransformExpression(def_elem->arg); + if (expr->expression_class != ExpressionClass::CONSTANT) { + throw InvalidInputException("Create index option must be a constant value"); + } + auto &const_expr = expr->Cast(); + val = const_expr.value; } else { val = Value::BOOLEAN(true); } diff --git a/src/duckdb/src/parser/transform/statement/transform_create_table.cpp b/src/duckdb/src/parser/transform/statement/transform_create_table.cpp index 412a73cd3..8a180497d 100644 --- a/src/duckdb/src/parser/transform/statement/transform_create_table.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_create_table.cpp @@ -1,6 +1,8 @@ #include "duckdb/catalog/catalog_entry/table_column_type.hpp" #include "duckdb/parser/constraint.hpp" #include "duckdb/parser/expression/collate_expression.hpp" +#include "duckdb/parser/expression/constant_expression.hpp" +#include "duckdb/parser/expression/type_expression.hpp" #include "duckdb/parser/parsed_data/create_table_info.hpp" #include "duckdb/parser/statement/create_statement.hpp" #include "duckdb/parser/transformer.hpp" @@ -59,18 +61,30 @@ ColumnDefinition Transformer::TransformColumnDefinition(duckdb_libpgquery::PGCol } else if (!cdef.typeName) { // ALTER TABLE tbl ALTER TYPE USING ... target_type = LogicalType::UNKNOWN; - } else { - target_type = TransformTypeName(*cdef.typeName); - } - - if (cdef.collClause) { + } else if (cdef.collClause) { if (cdef.category == duckdb_libpgquery::COL_GENERATED) { throw ParserException("Collations are not supported on generated columns"); } - if (target_type.id() != LogicalTypeId::VARCHAR) { + + auto typename_expr = TransformTypeExpressionInternal(*cdef.typeName); + if (typename_expr->type != ExpressionType::TYPE) { + throw ParserException("Only type names can have collations!"); + } + + auto &type_expr = typename_expr->Cast(); + if (!StringUtil::CIEquals(type_expr.GetTypeName(), "VARCHAR")) { throw ParserException("Only VARCHAR columns can have collations!"); } - target_type = LogicalType::VARCHAR_COLLATION(TransformCollation(cdef.collClause)); + + // Push back collation as a parameter of the type expression + auto collation = TransformCollation(cdef.collClause); + auto collation_expr = make_uniq(Value(collation)); + collation_expr->SetAlias("collation"); + type_expr.GetChildren().push_back(std::move(collation_expr)); + + target_type = LogicalType::UNBOUND(std::move(typename_expr)); + } else { + target_type = TransformTypeName(*cdef.typeName); } return ColumnDefinition(name, target_type); @@ -134,6 +148,22 @@ unique_ptr Transformer::TransformCreateTable(duckdb_libpgquery: } } + vector> partition_keys; + if (stmt.partition_list) { + TransformExpressionList(*stmt.partition_list, partition_keys); + } + info->partition_keys = std::move(partition_keys); + + vector> order_keys; + if (stmt.sort_list) { + TransformExpressionList(*stmt.sort_list, order_keys); + } + info->sort_keys = std::move(order_keys); + + if (stmt.options) { + TransformTableOptions(info->options, stmt.options); + } + if (!column_count) { throw ParserException("Table must have at least one column!"); } diff --git a/src/duckdb/src/parser/transform/statement/transform_create_table_as.cpp b/src/duckdb/src/parser/transform/statement/transform_create_table_as.cpp index 16ab1b596..35bdcb4a9 100644 --- a/src/duckdb/src/parser/transform/statement/transform_create_table_as.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_create_table_as.cpp @@ -1,7 +1,8 @@ -#include "duckdb/parser/statement/create_statement.hpp" #include "duckdb/parser/expression/constant_expression.hpp" +#include "duckdb/parser/expression/star_expression.hpp" #include "duckdb/parser/parsed_data/create_table_info.hpp" #include "duckdb/parser/query_node/select_node.hpp" +#include "duckdb/parser/statement/create_statement.hpp" #include "duckdb/parser/tableref/subqueryref.hpp" #include "duckdb/parser/transformer.hpp" @@ -11,7 +12,7 @@ unique_ptr Transformer::TransformCreateTableAs(duckdb_libpgquer if (stmt.relkind == duckdb_libpgquery::PG_OBJECT_MATVIEW) { throw NotImplementedException("Materialized view not implemented"); } - if (stmt.is_select_into || stmt.into->options) { + if (stmt.is_select_into) { throw NotImplementedException("Unimplemented features for CREATE TABLE as"); } if (stmt.query->type != duckdb_libpgquery::T_PGSelectStmt) { @@ -26,6 +27,22 @@ unique_ptr Transformer::TransformCreateTableAs(duckdb_libpgquer } auto query = TransformSelectStmt(*stmt.query, false); + vector> partition_keys; + if (stmt.into->partition_list) { + TransformExpressionList(*stmt.into->partition_list, partition_keys); + } + info->partition_keys = std::move(partition_keys); + + vector> order_keys; + if (stmt.into->sort_list) { + TransformExpressionList(*stmt.into->sort_list, order_keys); + } + info->sort_keys = std::move(order_keys); + + if (stmt.into->options) { + TransformTableOptions(info->options, *stmt.into->options); + } + // push a LIMIT 0 if 'WITH NO DATA' is specified if (stmt.into->skipData) { auto limit_modifier = make_uniq(); @@ -46,6 +63,7 @@ unique_ptr Transformer::TransformCreateTableAs(duckdb_libpgquer info->columns.AddColumn(ColumnDefinition(cols[i], LogicalType::UNKNOWN)); } } + info->catalog = qname.catalog; info->schema = qname.schema; info->table = qname.name; diff --git a/src/duckdb/src/parser/transform/statement/transform_secret.cpp b/src/duckdb/src/parser/transform/statement/transform_secret.cpp index bde6c38f7..749cde6e9 100644 --- a/src/duckdb/src/parser/transform/statement/transform_secret.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_secret.cpp @@ -1,6 +1,7 @@ -#include "duckdb/parser/statement/create_statement.hpp" +#include "duckdb/parser/expression/columnref_expression.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/function_expression.hpp" +#include "duckdb/parser/statement/create_statement.hpp" #include "duckdb/parser/tableref/basetableref.hpp" #include "duckdb/parser/transformer.hpp" diff --git a/src/duckdb/src/parser/transform/statement/transform_show.cpp b/src/duckdb/src/parser/transform/statement/transform_show.cpp index ebd0ebd8d..cc6afe780 100644 --- a/src/duckdb/src/parser/transform/statement/transform_show.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_show.cpp @@ -31,12 +31,15 @@ unique_ptr Transformer::TransformShow(duckdb_libpgquery::PGVariableSh } else { // describing a set (e.g. SHOW ALL TABLES) - push it in the table name showref->table_name = stmt.set; + showref->show_type = ShowType::SHOW_UNQUALIFIED; } } else if (!stmt.relation->schemaname) { // describing an unqualified relation - check if this is a "special" relation string table_name = StringUtil::Lower(stmt.relation->relname); - if (table_name == "databases" || table_name == "tables" || table_name == "variables") { + if (table_name == "databases" || table_name == "schemas" || table_name == "tables" || + table_name == "variables") { showref->table_name = "\"" + std::move(table_name) + "\""; + showref->show_type = ShowType::SHOW_UNQUALIFIED; } } if (showref->table_name.empty() && showref->show_type != ShowType::SHOW_FROM) { diff --git a/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp b/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp index dcb2dc036..a48fa76c3 100644 --- a/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp +++ b/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp @@ -8,39 +8,6 @@ namespace duckdb { -bool Transformer::TransformPivotInList(unique_ptr &expr, PivotColumnEntry &entry, bool root_entry) { - switch (expr->GetExpressionType()) { - case ExpressionType::COLUMN_REF: { - auto &colref = expr->Cast(); - if (colref.IsQualified()) { - throw ParserException(expr->GetQueryLocation(), "PIVOT IN list cannot contain qualified column references"); - } - entry.values.emplace_back(colref.GetColumnName()); - return true; - } - case ExpressionType::FUNCTION: { - auto &function = expr->Cast(); - if (function.function_name != "row") { - return false; - } - for (auto &child : function.children) { - if (!TransformPivotInList(child, entry, false)) { - return false; - } - } - return true; - } - default: { - Value val; - if (!Transformer::ConstructConstantFromExpression(*expr, val)) { - return false; - } - entry.values.push_back(std::move(val)); - return true; - } - } -} - PivotColumn Transformer::TransformPivotColumn(duckdb_libpgquery::PGPivot &pivot, bool is_pivot) { PivotColumn col; if (pivot.pivot_columns) { @@ -65,19 +32,7 @@ PivotColumn Transformer::TransformPivotColumn(duckdb_libpgquery::PGPivot &pivot, auto expr = TransformExpression(n); PivotColumnEntry entry; entry.alias = expr->GetAlias(); - auto transformed = TransformPivotInList(expr, entry); - if (!transformed) { - // could not transform into list of constant values - if (is_pivot) { - // for pivot - throw an exception - throw ParserException(expr->GetQueryLocation(), - "PIVOT IN list must contain columns or lists of columns"); - } else { - // for unpivot - we can forward the expression immediately - entry.values.clear(); - entry.expr = std::move(expr); - } - } + entry.expr = std::move(expr); col.entries.push_back(std::move(entry)); } } @@ -123,20 +78,6 @@ unique_ptr Transformer::TransformPivot(duckdb_libpgquery::PGPivotExpr throw ParserException("UNPIVOT requires a single column name for the PIVOT IN clause"); } D_ASSERT(pivot.pivot_expressions.empty()); - } else { - // pivot - auto expected_size = pivot.pivot_expressions.size(); - D_ASSERT(pivot.unpivot_names.empty()); - for (auto &entry : pivot.entries) { - if (entry.expr) { - throw ParserException("PIVOT IN list must contain columns or lists of columns - expressions are " - "only supported for UNPIVOT"); - } - if (entry.values.size() != expected_size) { - throw ParserException("PIVOT IN list - inconsistent amount of rows - expected %d but got %d", - expected_size, entry.values.size()); - } - } } } result->include_nulls = root.include_nulls; diff --git a/src/duckdb/src/parser/transformer.cpp b/src/duckdb/src/parser/transformer.cpp index f3f058899..b489ef086 100644 --- a/src/duckdb/src/parser/transformer.cpp +++ b/src/duckdb/src/parser/transformer.cpp @@ -244,4 +244,29 @@ void Transformer::SetQueryLocation(TableRef &ref, int query_location) { ref.query_location = optional_idx(static_cast(query_location)); } +void Transformer::TransformTableOptions(case_insensitive_map_t> &options, + optional_ptr pg_options, bool throw_if_value) { + if (!pg_options) { + return; + } + + duckdb_libpgquery::PGListCell *cell; + for_each_cell(cell, pg_options->head) { + auto def_elem = PGPointerCast(cell->data.ptr_value); + auto lower_name = StringUtil::Lower(def_elem->defname); + if (options.find(lower_name) != options.end()) { + throw ParserException("Duplicate table property \"%s\"", lower_name); + } + if (!def_elem->arg) { + options.emplace(lower_name, make_uniq(Value())); + continue; + } + auto expr = TransformExpression(def_elem->arg); + if (throw_if_value) { + throw ParserException("\"%s\"", expr->ToString()); + } + options.emplace(lower_name, std::move(expr)); + } +} + } // namespace duckdb diff --git a/src/duckdb/src/planner/bind_context.cpp b/src/duckdb/src/planner/bind_context.cpp index 470a8bc37..d588f8805 100644 --- a/src/duckdb/src/planner/bind_context.cpp +++ b/src/duckdb/src/planner/bind_context.cpp @@ -34,7 +34,7 @@ string MinimumUniqueAlias(const BindingAlias &alias, const BindingAlias &other) return alias.ToString(); } -optional_ptr BindContext::GetMatchingBinding(const string &column_name) { +optional_ptr BindContext::GetMatchingBinding(const string &column_name, QueryErrorContext context) { optional_ptr result; for (auto &binding_ptr : bindings_list) { auto &binding = *binding_ptr; @@ -45,6 +45,7 @@ optional_ptr BindContext::GetMatchingBinding(const string &column_name) if (binding.HasMatchingBinding(column_name)) { if (result || is_using_binding) { throw BinderException( + context, "Ambiguous reference to column name \"%s\" (use: \"%s.%s\" " "or \"%s.%s\")", column_name, MinimumUniqueAlias(result->GetBindingAlias(), binding.GetBindingAlias()), column_name, @@ -548,7 +549,7 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, auto binding = GetBinding(expr.relation_name, error); bool is_struct_ref = false; if (!binding) { - binding = GetMatchingBinding(expr.relation_name); + binding = GetMatchingBinding(expr.relation_name, expr); if (!binding) { error.Throw(); } diff --git a/src/duckdb/src/planner/binder.cpp b/src/duckdb/src/planner/binder.cpp index fe1b59cf3..c9d753513 100644 --- a/src/duckdb/src/planner/binder.cpp +++ b/src/duckdb/src/planner/binder.cpp @@ -7,6 +7,7 @@ #include "duckdb/common/helper.hpp" #include "duckdb/main/config.hpp" #include "duckdb/main/database.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/optimizer/optimizer.hpp" #include "duckdb/parser/expression/function_expression.hpp" #include "duckdb/parser/expression/subquery_expression.hpp" @@ -34,10 +35,11 @@ idx_t Binder::GetBinderDepth() const { void Binder::IncreaseDepth() { depth++; - if (depth > context.config.max_expression_depth) { + auto max_expression_depth = Settings::Get(context); + if (depth > max_expression_depth) { throw BinderException("Max expression depth limit of %lld exceeded. Use \"SET max_expression_depth TO x\" to " "increase the maximum expression depth.", - context.config.max_expression_depth); + max_expression_depth); } } @@ -421,4 +423,18 @@ optional_ptr Binder::GetCatalogEntry(const string &catalog, const return entry_retriever.GetEntry(catalog, schema, lookup_info, on_entry_not_found); } +//! Create a binder whose catalog search path is anchored to the table's catalog+schema +shared_ptr Binder::CreateBinderWithSearchPath(const string &catalog_name, const string &schema_name) { + shared_ptr new_binder = Binder::CreateBinder(context, this); + + vector search_path; + + search_path.emplace_back(catalog_name, schema_name); + if (schema_name != DEFAULT_SCHEMA) { + search_path.emplace_back(catalog_name, DEFAULT_SCHEMA); + } + new_binder->entry_retriever.SetSearchPath(std::move(search_path)); + return new_binder; +} + } // namespace duckdb diff --git a/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp index 053576294..9441c419c 100644 --- a/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp @@ -160,7 +160,7 @@ BindResult BaseSelectBinder::BindAggregate(FunctionExpression &aggr, AggregateFu if (order.expression->GetExpressionType() == ExpressionType::VALUE_CONSTANT) { auto &const_expr = order.expression->Cast(); if (!const_expr.value.type().IsIntegral()) { - auto order_by_non_integer_literal = DBConfig::GetSetting(context); + auto order_by_non_integer_literal = Settings::Get(context); if (!order_by_non_integer_literal) { throw BinderException( *order.expression, diff --git a/src/duckdb/src/planner/binder/expression/bind_collate_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_collate_expression.cpp index 0bcb8d213..13988462e 100644 --- a/src/duckdb/src/planner/binder/expression/bind_collate_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_collate_expression.cpp @@ -16,7 +16,7 @@ BindResult ExpressionBinder::BindExpression(CollateExpression &expr, idx_t depth throw ParameterNotResolvedException(); } if (child->return_type.id() != LogicalTypeId::VARCHAR) { - throw BinderException("collations are only supported for type varchar"); + throw BinderException(child->query_location, "collations are only supported for type varchar"); } // Validate the collation, but don't use it auto collation_test = make_uniq_base(Value(child->return_type)); diff --git a/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp index ca6824599..45d541d9e 100644 --- a/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp @@ -54,7 +54,8 @@ unique_ptr ExpressionBinder::GetSQLValueFunction(const string return make_uniq(value_function, std::move(children)); } -unique_ptr ExpressionBinder::QualifyColumnName(const string &column_name, ErrorData &error) { +unique_ptr ExpressionBinder::QualifyColumnName(const ParsedExpression &expr, + const string &column_name, ErrorData &error) { auto using_binding = binder.bind_context.GetUsingBinding(column_name); if (using_binding) { // we are referencing a USING column @@ -81,14 +82,14 @@ unique_ptr ExpressionBinder::QualifyColumnName(const string &c } // find a table binding that contains this column name - auto table_binding = binder.bind_context.GetMatchingBinding(column_name); + auto table_binding = binder.bind_context.GetMatchingBinding(column_name, expr); // throw an error if a macro parameter name conflicts with a column name auto is_macro_column = false; if (binder.macro_binding && binder.macro_binding->HasMatchingBinding(column_name)) { is_macro_column = true; if (table_binding) { - throw BinderException("Conflicting column names for column " + column_name + "!"); + throw BinderException(expr, "Conflicting column names for column " + column_name + "!"); } } @@ -341,7 +342,7 @@ unique_ptr ExpressionBinder::QualifyColumnNameWithManyDotsInte } // part1 could be a column ErrorData unused_error; - auto result_expr = QualifyColumnName(col_ref.column_names[0], unused_error); + auto result_expr = QualifyColumnName(col_ref, col_ref.column_names[0], unused_error); if (result_expr) { // it is! add the struct extract calls struct_extract_start = 1; @@ -462,7 +463,7 @@ unique_ptr ExpressionBinder::QualifyColumnName(ColumnRefExpres // no dots (i.e. "part1") // -> part1 refers to a column // check if we can qualify the column name with the table name - auto qualified_col_ref = QualifyColumnName(col_ref.GetColumnName(), error); + auto qualified_col_ref = QualifyColumnName(col_ref, col_ref.GetColumnName(), error); if (qualified_col_ref) { // we could: return it return qualified_col_ref; @@ -486,7 +487,7 @@ unique_ptr ExpressionBinder::QualifyColumnName(ColumnRefExpres // otherwise check if we can turn this into a struct extract ErrorData other_error; - auto qualified_col_ref = QualifyColumnName(col_ref.column_names[0], other_error); + auto qualified_col_ref = QualifyColumnName(col_ref, col_ref.column_names[0], other_error); if (qualified_col_ref) { // we could: create a struct extract return CreateStructExtract(std::move(qualified_col_ref), col_ref.column_names[1]); diff --git a/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp index 92a5d0757..a23480271 100644 --- a/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp @@ -13,6 +13,7 @@ #include "duckdb/planner/expression/bound_lambda_expression.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/expression_binder.hpp" +#include "duckdb/main/settings.hpp" namespace duckdb { @@ -23,14 +24,13 @@ BindResult ExpressionBinder::TryBindLambdaOrJson(FunctionExpression &function, i return BindLambdaFunction(function, func.Cast(), depth); } - auto &config = ClientConfig::GetConfig(context); - auto setting = config.lambda_syntax; + auto setting = Settings::Get(context); bool invalid_syntax = setting == LambdaSyntax::DISABLE_SINGLE_ARROW && syntax_type == LambdaSyntaxType::SINGLE_ARROW; bool warn_deprecated_syntax = setting == LambdaSyntax::DEFAULT && syntax_type == LambdaSyntaxType::SINGLE_ARROW; const string msg = "Deprecated lambda arrow (->) detected. Please transition to the new lambda syntax, " - "i.e.., lambda x, i: x + i, before DuckDB's next release. \n" - "Use SET lambda_syntax='ENABLE_SINGLE_ARROW' to revert to the deprecated behavior. \n" + "i.e.., lambda x, i: x + i, before DuckDB's next release.\n" + "Use SET lambda_syntax='ENABLE_SINGLE_ARROW' to revert to the deprecated behavior.\n" "For more information, see https://duckdb.org/docs/stable/sql/functions/lambda.html."; BindResult lambda_bind_result; @@ -220,12 +220,12 @@ BindResult ExpressionBinder::BindLambdaFunction(FunctionExpression &function, Sc } // the first child is the list, the second child is the lambda expression + // constexpr idx_t list_ix = 0; constexpr idx_t list_idx = 0; constexpr idx_t lambda_expr_idx = 1; D_ASSERT(function.children[lambda_expr_idx]->GetExpressionClass() == ExpressionClass::LAMBDA); vector function_child_types; - // bind the list ErrorData error; for (idx_t i = 0; i < function.children.size(); i++) { @@ -306,8 +306,9 @@ BindResult ExpressionBinder::BindLambdaFunction(FunctionExpression &function, Sc // push back (in reverse order) any nested lambda parameters so that we can later use them in the lambda // expression (rhs). This happens after we bound the lambda expression of this depth. So it is relevant for // correctly binding lambdas one level 'out'. Therefore, the current parameter count does not matter here. - idx_t offset = 0; if (lambda_bindings) { + idx_t offset = 0; + for (idx_t i = lambda_bindings->size(); i > 0; i--) { auto &binding = (*lambda_bindings)[i - 1]; auto &column_names = binding.GetColumnNames(); diff --git a/src/duckdb/src/planner/binder/expression/bind_lambda.cpp b/src/duckdb/src/planner/binder/expression/bind_lambda.cpp index 0d6334fc4..b6f77cafd 100644 --- a/src/duckdb/src/planner/binder/expression/bind_lambda.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_lambda.cpp @@ -12,7 +12,7 @@ namespace duckdb { -idx_t GetLambdaParamCount(vector &lambda_bindings) { +static idx_t GetLambdaParamCount(vector &lambda_bindings) { idx_t count = 0; for (auto &binding : lambda_bindings) { count += binding.GetColumnCount(); @@ -20,8 +20,8 @@ idx_t GetLambdaParamCount(vector &lambda_bindings) { return count; } -idx_t GetLambdaParamIndex(vector &lambda_bindings, const BoundLambdaExpression &bound_lambda_expr, - const BoundLambdaRefExpression &bound_lambda_ref_expr) { +static idx_t GetLambdaParamIndex(vector &lambda_bindings, const BoundLambdaExpression &bound_lambda_expr, + const BoundLambdaRefExpression &bound_lambda_ref_expr) { D_ASSERT(bound_lambda_ref_expr.lambda_idx < lambda_bindings.size()); idx_t offset = 0; // count the remaining lambda parameters BEFORE the current lambda parameter, @@ -35,7 +35,8 @@ idx_t GetLambdaParamIndex(vector &lambda_bindings, const BoundLamb return offset; } -void ExtractParameter(const ParsedExpression &expr, vector &column_names, vector &column_aliases) { +static void ExtractParameter(const ParsedExpression &expr, vector &column_names, + vector &column_aliases) { auto &column_ref = expr.Cast(); if (column_ref.IsQualified()) { throw BinderException(LambdaExpression::InvalidParametersErrorMessage()); @@ -45,7 +46,7 @@ void ExtractParameter(const ParsedExpression &expr, vector &column_names column_aliases.push_back(column_ref.ToString()); } -void ExtractParameters(LambdaExpression &expr, vector &column_names, vector &column_aliases) { +static void ExtractParameters(LambdaExpression &expr, vector &column_names, vector &column_aliases) { // extract the lambda parameters, which are a single column // reference, or a list of column references (ROW function) string error_message; diff --git a/src/duckdb/src/planner/binder/expression/bind_type_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_type_expression.cpp new file mode 100644 index 000000000..8754fe8e4 --- /dev/null +++ b/src/duckdb/src/planner/binder/expression/bind_type_expression.cpp @@ -0,0 +1,114 @@ +#include "duckdb/catalog/catalog.hpp" +#include "duckdb/execution/expression_executor.hpp" +#include "duckdb/planner/binder.hpp" +#include "duckdb/planner/expression/bound_constant_expression.hpp" +#include "duckdb/planner/expression_binder.hpp" +#include "duckdb/planner/expression_binder/constant_binder.hpp" +#include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" + +namespace duckdb { + +static bool IsValidTypeLookup(optional_ptr entry) { + if (!entry) { + return false; + } + return entry->Cast().user_type.id() != LogicalTypeId::INVALID; +} + +BindResult ExpressionBinder::BindExpression(TypeExpression &type_expr, idx_t depth) { + auto &type_name = type_expr.GetTypeName(); + auto type_schema = type_expr.GetSchema(); + auto type_catalog = type_expr.GetCatalog(); + + QueryErrorContext error_context(type_expr); + EntryLookupInfo type_lookup(CatalogType::TYPE_ENTRY, type_name, error_context); + + optional_ptr entry = nullptr; + + binder.BindSchemaOrCatalog(context, type_catalog, type_schema); + + // Required for WAL lookup to work + if (type_catalog.empty() && !DatabaseManager::Get(context).HasDefaultDatabase()) { + // Look in the system catalog if no catalog was specified + entry = binder.entry_retriever.GetEntry(SYSTEM_CATALOG, type_schema, type_lookup); + } else { + // Try to search from most specific to least specific + // The search path should already have been set to the correct catalog/schema, + // in case we are looking for a type in the same schema as a table we are creating + + entry = binder.entry_retriever.GetEntry(type_catalog, type_schema, type_lookup, OnEntryNotFound::RETURN_NULL); + + if (!IsValidTypeLookup(entry)) { + if (!type_catalog.empty() || !type_schema.empty()) { + entry = binder.entry_retriever.GetEntry(type_catalog, type_schema, type_lookup, + OnEntryNotFound::THROW_EXCEPTION); + } + entry = binder.entry_retriever.GetEntry(type_catalog, INVALID_SCHEMA, type_lookup, + OnEntryNotFound::RETURN_NULL); + } + if (!IsValidTypeLookup(entry)) { + entry = binder.entry_retriever.GetEntry(INVALID_CATALOG, INVALID_SCHEMA, type_lookup, + OnEntryNotFound::RETURN_NULL); + } + if (!IsValidTypeLookup(entry)) { + entry = binder.entry_retriever.GetEntry(SYSTEM_CATALOG, DEFAULT_SCHEMA, type_lookup, + OnEntryNotFound::THROW_EXCEPTION); + } + } + + // By this point we have to have found a type in the catalog + D_ASSERT(entry != nullptr); + auto &type_entry = entry->Cast(); + + // Now handle type parameters + auto &unbound_parameters = type_expr.GetChildren(); + + if (!type_entry.bind_function) { + if (!unbound_parameters.empty()) { + // This type does not support type parameters + throw BinderException(type_expr, "Type '%s' does not take any type parameters", type_name); + } + + // Otherwise, return the user type directly! + auto result_expr = make_uniq(Value::TYPE(type_entry.user_type)); + result_expr->query_location = type_expr.GetQueryLocation(); + return BindResult(std::move(result_expr)); + } + + // Bind value parameters + vector bound_parameters; + + for (auto ¶m : unbound_parameters) { + // Otherwise, try to fold it to a constant value + ConstantBinder binder(this->binder, context, StringUtil::Format("Type parameter for type '%s'", type_name)); + + auto expr = param->Copy(); + auto bound_expr = binder.Bind(expr); + + if (!bound_expr->IsFoldable()) { + throw BinderException(type_expr, "Type parameter expression for type '%s' is not a constant", type_name); + } + + // Shortcut for constant expressions + if (bound_expr->GetExpressionClass() == ExpressionClass::BOUND_CONSTANT) { + auto &const_expr = bound_expr->Cast(); + bound_parameters.emplace_back(param->GetAlias(), const_expr.value); + continue; + } + + // Otherwise we need to evaluate the expression + auto bound_param = ExpressionExecutor::EvaluateScalar(context, *bound_expr); + bound_parameters.emplace_back(param->GetAlias(), bound_param); + }; + + // Call the bind function + BindLogicalTypeInput input {context, type_entry.user_type, bound_parameters}; + auto result_type = type_entry.bind_function(input); + + // Return the resulting type! + auto result_expr = make_uniq(Value::TYPE(result_type)); + result_expr->query_location = type_expr.GetQueryLocation(); + return BindResult(std::move(result_expr)); +} + +} // namespace duckdb diff --git a/src/duckdb/src/planner/binder/query_node/bind_recursive_cte_node.cpp b/src/duckdb/src/planner/binder/query_node/bind_recursive_cte_node.cpp index efc9740de..18c0f5133 100644 --- a/src/duckdb/src/planner/binder/query_node/bind_recursive_cte_node.cpp +++ b/src/duckdb/src/planner/binder/query_node/bind_recursive_cte_node.cpp @@ -1,3 +1,4 @@ +#include "duckdb/common/enums/deprecated_using_key_syntax.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression_map.hpp" #include "duckdb/parser/query_node/select_node.hpp" @@ -5,6 +6,8 @@ #include "duckdb/planner/binder.hpp" #include "duckdb/planner/operator/logical_set_operation.hpp" #include "duckdb/planner/operator/logical_recursive_cte.hpp" +#include "duckdb/main/settings.hpp" +#include "duckdb/logging/logger.hpp" namespace duckdb { @@ -13,8 +16,32 @@ BoundStatement Binder::BindNode(RecursiveCTENode &statement) { // the left side is visited first and is added to the BindContext of the right side D_ASSERT(statement.left); D_ASSERT(statement.right); - if (statement.union_all && !statement.key_targets.empty()) { - throw BinderException("UNION ALL cannot be used with USING KEY in recursive CTE."); + + auto is_using_key = !statement.key_targets.empty(); + + if (is_using_key) { + auto setting = Settings::Get(context); + + // The USING KEY currently implement is actually the UNION ALL variant, + // but we use UNION syntax. This stands in the way of a possible addition of + // the UNION variant, so we will deprecate the UNION syntax for now (with + // the ability to still use it via a setting). Once enough time has elapsed + // and users have migrated relevant code to using UNION ALL syntax, we can + // declare the UNION syntax either as illegal syntax or implement the UNION + // variant proper (again with the ability to override the UNION syntax to + // use the "old" UNION ALL variant). + + bool warn_deprecated_syntax = setting == DeprecatedUsingKeySyntax::DEFAULT && !statement.union_all; + const string msg = + "Deprecated UNION in USING KEY CTE detected." + "Please transition to using UNION ALL, before DuckDB's next release. \n" + "Use SET deprecated_using_key_syntax='UNION_AS_UNION_ALL' to enable the deprecated behavior. \n" + "For more information, see " + "https://duckdb.org/docs/stable/sql/query_syntax/with#recursive-ctes-with-using-key."; + + if (warn_deprecated_syntax) { + DUCKDB_LOG_WARNING(context, msg); + } } auto ctename = statement.ctename; @@ -41,10 +68,9 @@ BoundStatement Binder::BindNode(RecursiveCTENode &statement) { // Add bindings of left side to temporary CTE bindings context BindingAlias cte_alias(statement.ctename); right_binder->bind_context.AddCTEBinding(setop_index, std::move(cte_alias), result.names, result.types); - if (!statement.key_targets.empty()) { - BindingAlias recurring_alias("recurring", statement.ctename); - right_binder->bind_context.AddCTEBinding(setop_index, std::move(recurring_alias), result.names, result.types); - } + + BindingAlias recurring_alias("recurring", statement.ctename); + right_binder->bind_context.AddCTEBinding(setop_index, std::move(recurring_alias), result.names, result.types); auto right = right_binder->BindNode(*statement.right); for (auto &c : left_binder->correlated_columns) { @@ -91,9 +117,6 @@ BoundStatement Binder::BindNode(RecursiveCTENode &statement) { auto recurring_binding = right_binder->GetCTEBinding(BindingAlias("recurring", ctename)); bool ref_recurring = recurring_binding && recurring_binding->IsReferenced(); - if (key_targets.empty() && ref_recurring) { - throw InvalidInputException("RECURRING can only be used with USING KEY in recursive CTE."); - } // Check if there is a reference to the recursive or recurring table, if not create a set operator. auto cte_binding = right_binder->GetCTEBinding(BindingAlias(ctename)); diff --git a/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp b/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp index ab162808e..40aad85bb 100644 --- a/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp +++ b/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp @@ -80,7 +80,7 @@ static unique_ptr PlanUncorrelatedSubquery(Binder &binder, BoundSubq D_ASSERT(bindings.size() == 1); idx_t table_idx = bindings[0].table_index; - bool error_on_multiple_rows = DBConfig::GetSetting(binder.context); + bool error_on_multiple_rows = Settings::Get(binder.context); // we push an aggregate that returns the FIRST element vector> expressions; diff --git a/src/duckdb/src/planner/binder/statement/bind_copy.cpp b/src/duckdb/src/planner/binder/statement/bind_copy.cpp index 7a6944b4a..b627e7fb1 100644 --- a/src/duckdb/src/planner/binder/statement/bind_copy.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_copy.cpp @@ -422,10 +422,21 @@ vector BindCopyOption(ClientContext &context, TableFunctionBinder &option return result; } } + const bool is_partition_by = StringUtil::CIEquals(name, "partition_by"); + + if (is_partition_by) { + //! When binding the 'partition_by' option, we don't want to resolve a column reference to a SQLValueFunction + //! (like 'user') + option_binder.DisableSQLValueFunctions(); + } auto bound_expr = option_binder.Bind(expr); if (bound_expr->HasParameter()) { throw ParameterNotResolvedException(); } + if (is_partition_by) { + option_binder.EnableSQLValueFunctions(); + } + auto val = ExpressionExecutor::EvaluateScalar(context, *bound_expr, true); if (val.IsNull()) { throw BinderException("NULL is not supported as a valid option for COPY option \"" + name + "\""); diff --git a/src/duckdb/src/planner/binder/statement/bind_create.cpp b/src/duckdb/src/planner/binder/statement/bind_create.cpp index 01467054f..6d4a86406 100644 --- a/src/duckdb/src/planner/binder/statement/bind_create.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_create.cpp @@ -44,6 +44,8 @@ #include "duckdb/common/type_visitor.hpp" #include "duckdb/function/table_macro_function.hpp" #include "duckdb/main/settings.hpp" +#include "duckdb/parser/expression/type_expression.hpp" +#include "duckdb/planner/expression/bound_constant_expression.hpp" namespace duckdb { @@ -159,36 +161,41 @@ void Binder::SetCatalogLookupCallback(catalog_entry_callback_t callback) { entry_retriever.SetCallback(std::move(callback)); } -void Binder::BindCreateViewInfo(CreateViewInfo &base) { - // bind the view as if it were a query so we can catch errors - // note that we bind the original, and replace the original with a copy +void Binder::BindView(ClientContext &context, const SelectStatement &stmt, const string &catalog_name, + const string &schema_name, optional_ptr dependencies, + const vector &aliases, vector &result_types, vector &result_names) { auto view_binder = Binder::CreateBinder(context); - auto &dependencies = base.dependencies; - auto &catalog = Catalog::GetCatalog(context, base.catalog); + auto &catalog = Catalog::GetCatalog(context, catalog_name); - bool should_create_dependencies = DBConfig::GetSetting(context); - if (should_create_dependencies) { + if (dependencies) { view_binder->SetCatalogLookupCallback([&dependencies, &catalog](CatalogEntry &entry) { if (&catalog != &entry.ParentCatalog()) { // Don't register dependencies between catalogs return; } - dependencies.AddDependency(entry); + dependencies->AddDependency(entry); }); } view_binder->can_contain_nulls = true; - auto view_search_path = GetSearchPath(catalog, base.schema); + auto view_search_path = view_binder->GetSearchPath(catalog, schema_name); view_binder->entry_retriever.SetSearchPath(std::move(view_search_path)); - auto copy = base.query->Copy(); - auto query_node = view_binder->Bind(*base.query); - base.query = unique_ptr_cast(std::move(copy)); - if (base.aliases.size() > query_node.names.size()) { + auto copy = stmt.Copy(); + auto query_node = view_binder->Bind(*copy); + if (aliases.size() > query_node.names.size()) { throw BinderException("More VIEW aliases than columns in query result"); } - base.types = query_node.types; - base.names = query_node.names; + result_types = query_node.types; + result_names = query_node.names; +} + +void Binder::BindCreateViewInfo(CreateViewInfo &base) { + optional_ptr dependencies; + if (Settings::Get(context)) { + dependencies = base.dependencies; + } + BindView(context, *base.query, base.catalog, base.schema, dependencies, base.aliases, base.types, base.names); } SchemaCatalogEntry &Binder::BindCreateFunctionInfo(CreateInfo &info) { @@ -264,14 +271,40 @@ SchemaCatalogEntry &Binder::BindCreateFunctionInfo(CreateInfo &info) { }); } + // Constant-fold all default parameter expressions + for (auto &it : function->default_parameters) { + auto ¶m_name = it.first; + auto ¶m_expr = it.second; + + if (param_expr->type == ExpressionType::VALUE_CONSTANT) { + continue; + } + + ConstantBinder binder(*this, context, StringUtil::Format("Default value for parameter '%s'", param_name)); + auto default_expr = param_expr->Copy(); + auto bound_default = binder.Bind(default_expr); + if (!bound_default->IsFoldable()) { + auto msg = StringUtil::Format("Default value '%s' for parameter '%s' is not a constant expression.", + param_expr->ToString(), param_name); + throw BinderException(msg); + } + + auto default_val = ExpressionExecutor::EvaluateScalar(context, *bound_default); + + // Save this back as a constant expression + auto const_expr = make_uniq(default_val); + const_expr->alias = param_name; + it.second = std::move(const_expr); + } + // Resolve any user type arguments for (idx_t param_idx = 0; param_idx < function->types.size(); param_idx++) { auto &type = function->types[param_idx]; if (type.id() == LogicalTypeId::UNKNOWN) { continue; } - if (type.id() == LogicalTypeId::USER) { - type = TransformStringToLogicalType(type.ToString(), context); + if (type.id() == LogicalTypeId::UNBOUND) { + BindLogicalType(type); } const auto ¶m_name = function->parameters[param_idx]->Cast().GetColumnName(); auto it = function->default_parameters.find(param_name); @@ -304,7 +337,7 @@ SchemaCatalogEntry &Binder::BindCreateFunctionInfo(CreateInfo &info) { macro_binding = this_macro_binding.get(); auto &dependencies = base.dependencies; - const auto should_create_dependencies = DBConfig::GetSetting(context); + const auto should_create_dependencies = Settings::Get(context); const auto binder_callback = [&dependencies, &catalog](CatalogEntry &entry) { if (&catalog != &entry.ParentCatalog()) { // Don't register any cross-catalog dependencies @@ -364,132 +397,49 @@ SchemaCatalogEntry &Binder::BindCreateFunctionInfo(CreateInfo &info) { return BindCreateSchema(info); } -static bool IsValidUserType(optional_ptr entry) { - if (!entry) { - return false; - } - return entry->Cast().user_type.id() != LogicalTypeId::INVALID; -} +LogicalType Binder::BindLogicalTypeInternal(const unique_ptr &type_expr) { + ConstantBinder binder(*this, context, "Type binding"); + auto copy = type_expr->Copy(); + auto expr = binder.Bind(copy); -LogicalType Binder::BindLogicalTypeInternal(const LogicalType &type, optional_ptr catalog, - const string &schema) { - if (type.id() != LogicalTypeId::USER) { - // Nested type, make sure to bind any nested user types recursively - LogicalType result; - switch (type.id()) { - case LogicalTypeId::LIST: { - auto child_type = BindLogicalTypeInternal(ListType::GetChildType(type), catalog, schema); - result = LogicalType::LIST(child_type); - break; - } - case LogicalTypeId::MAP: { - auto key_type = BindLogicalTypeInternal(MapType::KeyType(type), catalog, schema); - auto value_type = BindLogicalTypeInternal(MapType::ValueType(type), catalog, schema); - result = LogicalType::MAP(std::move(key_type), std::move(value_type)); - break; - } - case LogicalTypeId::ARRAY: { - auto child_type = BindLogicalTypeInternal(ArrayType::GetChildType(type), catalog, schema); - auto array_size = ArrayType::GetSize(type); - result = LogicalType::ARRAY(child_type, array_size); - break; - } - case LogicalTypeId::STRUCT: { - auto child_types = StructType::GetChildTypes(type); - child_list_t new_child_types; - for (auto &entry : child_types) { - new_child_types.emplace_back(entry.first, BindLogicalTypeInternal(entry.second, catalog, schema)); - } - result = LogicalType::STRUCT(std::move(new_child_types)); - break; - } - case LogicalTypeId::UNION: { - child_list_t member_types; - for (idx_t i = 0; i < UnionType::GetMemberCount(type); i++) { - auto child_type = BindLogicalTypeInternal(UnionType::GetMemberType(type, i), catalog, schema); - member_types.emplace_back(UnionType::GetMemberName(type, i), std::move(child_type)); - } - result = LogicalType::UNION(std::move(member_types)); - break; - } - default: - return type; - } - - // Set the alias and extension info back - result.SetAlias(type.GetAlias()); - auto ext_info = type.HasExtensionInfo() ? make_uniq(*type.GetExtensionInfo()) : nullptr; - result.SetExtensionInfo(std::move(ext_info)); - return result; + if (!expr->IsFoldable()) { + throw BinderException(*type_expr, "Type expression is not constant"); } - // User type, bind the user type - auto user_type_name = UserType::GetTypeName(type); - auto user_type_schema = UserType::GetSchema(type); - auto user_type_mods = UserType::GetTypeModifiers(type); - - bind_logical_type_function_t user_bind_modifiers_func = nullptr; - - LogicalType result; - EntryLookupInfo type_lookup(CatalogType::TYPE_ENTRY, user_type_name); - if (catalog) { - // The search order is: - // 1) In the explicitly set schema (my_schema.my_type) - // 2) In the same schema as the table - // 3) In the same catalog - // 4) System catalog - - optional_ptr entry = nullptr; - if (!user_type_schema.empty()) { - entry = entry_retriever.GetEntry(*catalog, user_type_schema, type_lookup, OnEntryNotFound::RETURN_NULL); - } - if (!IsValidUserType(entry)) { - entry = entry_retriever.GetEntry(*catalog, schema, type_lookup, OnEntryNotFound::RETURN_NULL); - } - if (!IsValidUserType(entry)) { - entry = entry_retriever.GetEntry(*catalog, INVALID_SCHEMA, type_lookup, OnEntryNotFound::RETURN_NULL); - } - if (!IsValidUserType(entry)) { - entry = entry_retriever.GetEntry(INVALID_CATALOG, INVALID_SCHEMA, type_lookup, - OnEntryNotFound::THROW_EXCEPTION); - } - auto &type_entry = entry->Cast(); - result = type_entry.user_type; - user_bind_modifiers_func = type_entry.bind_function; - } else { - string type_catalog = UserType::GetCatalog(type); - string type_schema = UserType::GetSchema(type); - - BindSchemaOrCatalog(context, type_catalog, type_schema); - auto entry = entry_retriever.GetEntry(type_catalog, type_schema, type_lookup); - auto &type_entry = entry->Cast(); - result = type_entry.user_type; - user_bind_modifiers_func = type_entry.bind_function; + if (expr->return_type != LogicalTypeId::TYPE) { + throw BinderException(*type_expr, "Expected a type returning expression, but got expression of type '%s'", + expr->return_type.ToString()); } - // Now we bind the inner user type - BindLogicalType(result, catalog, schema); - - // Apply the type modifiers (if any) - if (user_bind_modifiers_func) { - // If an explicit bind_modifiers function was provided, use that to construct the type - - BindLogicalTypeInput input {context, result, user_type_mods}; - result = user_bind_modifiers_func(input); - } else { - if (!user_type_mods.empty()) { - throw BinderException("Type '%s' does not take any type modifiers", user_type_name); - } + // Shortcut for constant expressions + if (expr->GetExpressionClass() == ExpressionClass::BOUND_CONSTANT) { + auto &const_expr = expr->Cast(); + return TypeValue::GetType(const_expr.value); } - return result; + + // Else, evaluate the type expression + auto type_value = ExpressionExecutor::EvaluateScalar(context, *expr); + D_ASSERT(type_value.type().id() == LogicalTypeId::TYPE); + return TypeValue::GetType(type_value); } -void Binder::BindLogicalType(LogicalType &type, optional_ptr catalog, const string &schema) { - // check if we need to bind this type at all - if (!TypeVisitor::Contains(type, LogicalTypeId::USER)) { +void Binder::BindLogicalType(LogicalType &type) { + // Check if we need to bind this type at all + if (!TypeVisitor::Contains(type, LogicalTypeId::UNBOUND)) { return; } - type = BindLogicalTypeInternal(type, catalog, schema); + + // Replace all unbound types within the type + // Normally, the unbound type is the root type, but it can also be nested within other types if we e.g. + // alter-table and change a struct field. + type = TypeVisitor::VisitReplace(type, [&](const LogicalType &ty) { + if (ty.id() == LogicalTypeId::UNBOUND) { + auto &type_expr = UnboundType::GetTypeExpression(ty); + return BindLogicalTypeInternal(type_expr); + } + + return ty; + }); } unique_ptr DuckCatalog::BindCreateIndex(Binder &binder, CreateStatement &stmt, @@ -621,26 +571,10 @@ BoundStatement Binder::Bind(CreateStatement &stmt) { } result.plan->AddChild(std::move(query)); - } else if (create_type_info.type.id() == LogicalTypeId::USER) { - SetCatalogLookupCallback(dependency_callback); - // two cases: - // 1: create a type with a non-existent type as source, Binder::BindLogicalType(...) will throw exception. - // 2: create a type alias with a custom type. - // eg. CREATE TYPE a AS INT; CREATE TYPE b AS a; - // We set b to be an alias for the underlying type of a - - EntryLookupInfo type_lookup(CatalogType::TYPE_ENTRY, UserType::GetTypeName(create_type_info.type)); - auto type_entry_p = entry_retriever.GetEntry(schema.catalog.GetName(), schema.name, type_lookup); - D_ASSERT(type_entry_p); - auto &type_entry = type_entry_p->Cast(); - create_type_info.type = type_entry.user_type; } else { SetCatalogLookupCallback(dependency_callback); - // This is done so that if the type contains a USER type, - // we register this dependency - auto preserved_type = create_type_info.type; + // Bind the underlying type BindLogicalType(create_type_info.type); - create_type_info.type = preserved_type; } break; } diff --git a/src/duckdb/src/planner/binder/statement/bind_create_table.cpp b/src/duckdb/src/planner/binder/statement/bind_create_table.cpp index ac8a32f65..39dfa0328 100644 --- a/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_create_table.cpp @@ -23,6 +23,7 @@ #include "duckdb/parser/parsed_expression_iterator.hpp" #include "duckdb/storage/data_table.hpp" #include "duckdb/storage/storage_manager.hpp" +#include "duckdb/common/type_visitor.hpp" namespace duckdb { @@ -55,7 +56,7 @@ static void VerifyCompressionType(ClientContext &context, optional_ptr( context, INVALID_CATALOG, INVALID_SCHEMA, logical_type.GetAlias(), OnEntryNotFound::RETURN_NULL); @@ -67,7 +68,7 @@ static void VerifyCompressionType(ClientContext &context, optional_ptrSetColumnType(i.index, col.Type()); + } else if (col.Type().id() == LogicalTypeId::UNBOUND) { + // Bind column type + BindLogicalType(col.TypeMutable()); + table_binding->SetColumnType(i.index, col.Type()); } + bound_indices.insert(i); } } @@ -311,14 +318,7 @@ void Binder::BindDefaultValues(const ColumnList &columns, vector defaults_search_path; - defaults_search_path.emplace_back(catalog_name, schema_name); - if (schema_name != DEFAULT_SCHEMA) { - defaults_search_path.emplace_back(catalog_name, DEFAULT_SCHEMA); - } - - auto default_binder = Binder::CreateBinder(context, *this); - default_binder->entry_retriever.SetSearchPath(std::move(defaults_search_path)); + auto default_binder = CreateBinderWithSearchPath(catalog_name, schema_name); for (auto &column : columns.Physical()) { unique_ptr bound_default; @@ -352,8 +352,8 @@ unique_ptr Binder::BindCreateTableCheckpoint(unique_ptr &gcols, - bool &contains_gcol) { +static void ExpressionContainsGeneratedColumn(const ParsedExpression &root_expr, const unordered_set &gcols, + bool &contains_gcol) { ParsedExpressionIterator::VisitExpression(root_expr, [&](const ColumnRefExpression &column_ref) { auto &name = column_ref.GetColumnName(); @@ -562,6 +562,7 @@ static void BindCreateTableConstraints(CreateTableInfo &create_info, CatalogEntr } auto &pk_table_entry_ptr = table_entry->Cast(); + fk.info.schema = pk_table_entry_ptr.schema.name; if (&pk_table_entry_ptr.schema != &schema) { throw BinderException("Creating foreign keys across different schemas or catalogs is not supported"); } @@ -596,6 +597,10 @@ unique_ptr Binder::BindCreateTableInfo(unique_ptrSetSearchPath(result->schema.catalog, result->schema.name); + vector> bound_constraints; if (base.query) { // construct the result object @@ -631,23 +636,34 @@ unique_ptr Binder::BindCreateTableInfo(unique_ptrschema.catalog, result->schema.name); + type_binder->BindLogicalType(column.TypeMutable()); } + } else { SetCatalogLookupCallback([&dependencies, &schema](CatalogEntry &entry) { if (&schema.ParentCatalog() != &entry.ParentCatalog()) { // Don't register dependencies between catalogs return; } + + if (entry.type == CatalogType::TYPE_ENTRY && entry.internal) { + // Don't register dependencies on internal types + return; + } + dependencies.AddDependency(entry); }); + // Bind all physical column types + for (idx_t i = 0; i < base.columns.PhysicalColumnCount(); i++) { + auto &column = base.columns.GetColumnMutable(PhysicalIndex(i)); + type_binder->BindLogicalType(column.TypeMutable()); + } + auto &config = DBConfig::Get(catalog.GetAttached()); VerifyCompressionType(context, storage_manager, config, *result); CreateColumnDependencyManager(*result); @@ -655,14 +671,6 @@ unique_ptr Binder::BindCreateTableInfo(unique_ptrschema.catalog, result->schema.name); - } BindCreateTableConstraints(base, entry_retriever, schema); if (AnyConstraintReferencesGeneratedColumn(base)) { @@ -681,6 +689,16 @@ unique_ptr Binder::BindCreateTableInfo(unique_ptrdependencies.VerifyDependencies(schema.catalog, result->Base().table); +#ifdef DEBUG + // Ensure all types are bound + for (idx_t i = 0; i < base.columns.LogicalColumnCount(); i++) { + auto &column = base.columns.GetColumn(LogicalIndex(i)); + if (TypeVisitor::Contains(column.Type(), LogicalTypeId::UNBOUND)) { + throw InternalException("Unbound type remaining in column \"%s\" during Create Table bind", column.Name()); + } + } +#endif + auto &properties = GetStatementProperties(); properties.output_type = QueryResultOutputType::FORCE_MATERIALIZED; return result; diff --git a/src/duckdb/src/planner/binder/statement/bind_insert.cpp b/src/duckdb/src/planner/binder/statement/bind_insert.cpp index f9c073ad9..0d44ac5ac 100644 --- a/src/duckdb/src/planner/binder/statement/bind_insert.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_insert.cpp @@ -387,9 +387,10 @@ unique_ptr Binder::GenerateMergeInto(InsertStatement &stmt, named_column_map.push_back(col.Logical()); } } else { + // Ensure that the columns are valid. for (auto &col_name : stmt.columns) { - auto &col = table.GetColumn(col_name); - named_column_map.push_back(col.Logical()); + auto col_idx = table.GetColumnIndex(col_name); + named_column_map.push_back(col_idx); } } ExpandDefaultInValuesList(stmt, table, values_list, named_column_map); diff --git a/src/duckdb/src/planner/binder/statement/bind_simple.cpp b/src/duckdb/src/planner/binder/statement/bind_simple.cpp index f21f26b9f..31869ac1b 100644 --- a/src/duckdb/src/planner/binder/statement/bind_simple.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_simple.cpp @@ -76,6 +76,28 @@ BoundStatement Binder::BindAlterAddIndex(BoundStatement &result, CatalogEntry &e return std::move(result); } +static void BindAlterTypes(Binder &binder, AlterStatement &stmt) { + if (stmt.info->type == AlterType::ALTER_TABLE) { + auto &table_info = stmt.info->Cast(); + switch (table_info.alter_table_type) { + case AlterTableType::ADD_COLUMN: { + auto &add_info = table_info.Cast(); + binder.BindLogicalType(add_info.new_column.TypeMutable()); + } break; + case AlterTableType::ADD_FIELD: { + auto &add_info = table_info.Cast(); + binder.BindLogicalType(add_info.new_field.TypeMutable()); + } break; + case AlterTableType::ALTER_COLUMN_TYPE: { + auto &alter_column_info = table_info.Cast(); + binder.BindLogicalType(alter_column_info.target_type); + } break; + default: + break; + } + } +} + BoundStatement Binder::Bind(AlterStatement &stmt) { BoundStatement result; result.names = {"Success"}; @@ -97,7 +119,11 @@ BoundStatement Binder::Bind(AlterStatement &stmt) { // Extra step for column comments: They can alter a table or a view, and we resolve that here. auto &info = stmt.info->Cast(); entry = info.TryResolveCatalogEntry(entry_retriever); - + if (entry && info.catalog_entry_type == CatalogType::VIEW_ENTRY) { + // when running SET COLUMN on a VIEW - ensure the view is bound + auto &view = entry->Cast(); + view.BindView(context); + } } else { // For any other ALTER, we retrieve the catalog entry directly. EntryLookupInfo lookup_info(stmt.info->GetCatalogType(), stmt.info->name); @@ -107,12 +133,22 @@ BoundStatement Binder::Bind(AlterStatement &stmt) { auto &properties = GetStatementProperties(); properties.return_type = StatementReturnType::NOTHING; if (!entry) { + // Bind types in this binder + BindAlterTypes(*this, stmt); + result.plan = make_uniq(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); return result; } D_ASSERT(!entry->deleted); auto &catalog = entry->ParentCatalog(); + + // Bind types in the same catalog as the entry + auto type_binder = Binder::CreateBinder(context, *this); + type_binder->SetSearchPath(catalog, stmt.info->schema); + + BindAlterTypes(*type_binder, stmt); + if (catalog.IsSystemCatalog()) { throw BinderException("Can not comment on System Catalog entries"); } diff --git a/src/duckdb/src/planner/binder/statement/bind_update.cpp b/src/duckdb/src/planner/binder/statement/bind_update.cpp index 1480000c6..c43ece2e6 100644 --- a/src/duckdb/src/planner/binder/statement/bind_update.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_update.cpp @@ -21,8 +21,18 @@ namespace duckdb { void Binder::BindUpdateSet(idx_t proj_index, unique_ptr &root, UpdateSetInfo &set_info, TableCatalogEntry &table, vector &columns, vector> &update_expressions, - vector> &projection_expressions) { + vector> &projection_expressions, bool prioritize_table_when_binding) { D_ASSERT(set_info.columns.size() == set_info.expressions.size()); + + Binder *expr_binder_ptr = this; + shared_ptr binder_with_search_path; + + if (prioritize_table_when_binding) { + binder_with_search_path = + CreateBinderWithSearchPath(table.ParentCatalog().GetName(), table.ParentSchema().name); + expr_binder_ptr = binder_with_search_path.get(); + } + for (idx_t i = 0; i < set_info.columns.size(); i++) { auto &colname = set_info.columns[i]; auto &expr = set_info.expressions[i]; @@ -45,7 +55,7 @@ void Binder::BindUpdateSet(idx_t proj_index, unique_ptr &root, if (expr->GetExpressionType() == ExpressionType::VALUE_DEFAULT) { update_expressions.push_back(make_uniq(column.Type())); } else { - UpdateBinder binder(*this, context); + UpdateBinder binder(*expr_binder_ptr, context); binder.target_type = column.Type(); auto bound_expr = binder.Bind(expr); PlanSubqueries(bound_expr, root); @@ -61,11 +71,12 @@ void Binder::BindUpdateSet(idx_t proj_index, unique_ptr &root, // unless there are no expressions to project, in which case it just returns 'root' unique_ptr Binder::BindUpdateSet(LogicalOperator &op, unique_ptr root, UpdateSetInfo &set_info, TableCatalogEntry &table, - vector &columns) { + vector &columns, bool prioritize_table_when_binding) { auto proj_index = GenerateTableIndex(); vector> projection_expressions; - BindUpdateSet(proj_index, root, set_info, table, columns, op.expressions, projection_expressions); + BindUpdateSet(proj_index, root, set_info, table, columns, op.expressions, projection_expressions, + prioritize_table_when_binding); if (op.type != LogicalOperatorType::LOGICAL_UPDATE && projection_expressions.empty()) { return root; } @@ -163,7 +174,8 @@ BoundStatement Binder::Bind(UpdateStatement &stmt) { D_ASSERT(stmt.set_info); D_ASSERT(stmt.set_info->columns.size() == stmt.set_info->expressions.size()); - auto proj_tmp = BindUpdateSet(*update, std::move(root), *stmt.set_info, table, update->columns); + auto proj_tmp = BindUpdateSet(*update, std::move(root), *stmt.set_info, table, update->columns, + stmt.prioritize_table_when_binding); D_ASSERT(proj_tmp->type == LogicalOperatorType::LOGICAL_PROJECTION); auto proj = unique_ptr_cast(std::move(proj_tmp)); diff --git a/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp b/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp index 6ff5d36f6..8b790b727 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp @@ -23,9 +23,7 @@ namespace duckdb { static bool TryLoadExtensionForReplacementScan(ClientContext &context, const string &table_name) { auto lower_name = StringUtil::Lower(table_name); - auto &dbconfig = DBConfig::GetConfig(context); - - if (!dbconfig.options.autoload_known_extensions) { + if (!Settings::Get(context)) { return false; } @@ -113,14 +111,9 @@ vector Binder::GetSearchPath(Catalog &catalog, const string return view_search_path; } -static vector ExchangeAllNullTypes(const vector &types) { - vector result = types; - for (auto &type : result) { - if (ExpressionBinder::ContainsNullType(type)) { - type = ExpressionBinder::ExchangeNullType(type); - } - } - return result; +void Binder::SetSearchPath(Catalog &catalog, const string &schema) { + auto search_path = GetSearchPath(catalog, schema); + entry_retriever.SetSearchPath(std::move(search_path)); } BoundStatement Binder::Bind(BaseTableRef &ref) { @@ -205,7 +198,7 @@ BoundStatement Binder::Bind(BaseTableRef &ref) { } } auto &config = DBConfig::GetConfig(context); - if (context.config.use_replacement_scans && config.options.enable_external_access && + if (context.config.use_replacement_scans && Settings::Get(config) && ExtensionHelper::IsFullPath(full_path)) { auto &fs = FileSystem::GetFileSystem(context); if (!fs.IsDisabledForPath(full_path) && fs.FileExists(full_path)) { @@ -295,13 +288,17 @@ BoundStatement Binder::Bind(BaseTableRef &ref) { SubqueryRef subquery(unique_ptr_cast(std::move(query))); subquery.alias = ref.alias; - // construct view names by first (1) taking the view aliases, (2) adding the view names, then (3) applying - // subquery aliases - vector view_names = view_catalog_entry.aliases; - for (idx_t n = view_names.size(); n < view_catalog_entry.names.size(); n++) { - view_names.push_back(view_catalog_entry.names[n]); + // construct view names by taking the view aliases + subquery.column_name_alias = view_catalog_entry.aliases; + // now apply the subquery column aliases + for (idx_t i = 0; i < ref.column_name_alias.size(); i++) { + if (i < subquery.column_name_alias.size()) { + // override alias + subquery.column_name_alias[i] = ref.column_name_alias[i]; + } else { + subquery.column_name_alias.push_back(ref.column_name_alias[i]); + } } - subquery.column_name_alias = BindContext::AliasColumnNames(ref.table_name, view_names, ref.column_name_alias); // when binding a view, we always look into the catalog/schema where the view is stored first auto view_search_path = @@ -316,31 +313,8 @@ BoundStatement Binder::Bind(BaseTableRef &ref) { if (!view_binder->correlated_columns.empty()) { throw BinderException("Contents of view were altered - view bound correlated columns"); } - - // verify that the types and names match up with the expected types and names if the view has type info defined - if (GetBindingMode() != BindingMode::EXTRACT_NAMES && - GetBindingMode() != BindingMode::EXTRACT_QUALIFIED_NAMES && view_catalog_entry.HasTypes()) { - // we bind the view subquery and the original view with different "can_contain_nulls", - // but we don't want to throw an error when SQLNULL does not match up with INTEGER, - // so we exchange all SQLNULL with INTEGER here before comparing - auto bound_types = ExchangeAllNullTypes(bound_child.types); - auto view_types = ExchangeAllNullTypes(view_catalog_entry.types); - if (bound_types != view_types) { - auto actual_types = StringUtil::ToString(bound_types, ", "); - auto expected_types = StringUtil::ToString(view_types, ", "); - throw BinderException( - "Contents of view were altered: types don't match! Expected [%s], but found [%s] instead", - expected_types, actual_types); - } - if (bound_child.names.size() == view_catalog_entry.names.size() && - bound_child.names != view_catalog_entry.names) { - auto actual_names = StringUtil::Join(bound_child.names, ", "); - auto expected_names = StringUtil::Join(view_catalog_entry.names, ", "); - throw BinderException( - "Contents of view were altered: names don't match! Expected [%s], but found [%s] instead", - expected_names, actual_names); - } - } + // update the view binding with the bound view information + view_catalog_entry.UpdateBinding(bound_child.types, bound_child.names); bind_context.AddView(bound_child.plan->GetRootIndex(), subquery.alias, subquery, bound_child, view_catalog_entry); return bound_child; diff --git a/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp b/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp index 99c131a89..3e1094e52 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp @@ -22,6 +22,8 @@ #include "duckdb/planner/operator/logical_aggregate.hpp" #include "duckdb/planner/operator/logical_pivot.hpp" #include "duckdb/main/settings.hpp" +#include "duckdb/execution/expression_executor.hpp" +#include "duckdb/planner/expression_binder/constant_binder.hpp" namespace duckdb { @@ -506,6 +508,37 @@ BoundStatement Binder::BindBoundPivot(PivotRef &ref) { return result_statement; } +static void BindPivotInList(unique_ptr &expr, vector &values, Binder &binder) { + switch (expr->GetExpressionType()) { + case ExpressionType::COLUMN_REF: { + auto &colref = expr->Cast(); + if (colref.IsQualified()) { + throw BinderException(expr->GetQueryLocation(), "PIVOT IN list cannot contain qualified column references"); + } + values.emplace_back(colref.GetColumnName()); + } break; + case ExpressionType::FUNCTION: { + auto &function = expr->Cast(); + if (function.function_name != "row") { + throw BinderException(expr->GetQueryLocation(), "PIVOT IN list must contain columns or lists of columns"); + } + for (auto &child : function.children) { + BindPivotInList(child, values, binder); + } + } break; + default: { + Value val; + ConstantBinder const_binder(binder, binder.context, "PIVOT IN list"); + auto bound_expr = const_binder.Bind(expr); + if (!bound_expr->IsFoldable()) { + throw BinderException(expr->GetQueryLocation(), "PIVOT IN list must contain constant expressions"); + } + auto folded_value = ExpressionExecutor::EvaluateScalar(binder.context, *bound_expr); + values.push_back(folded_value); + } break; + } +} + unique_ptr Binder::BindPivot(PivotRef &ref, vector> all_columns) { // keep track of the columns by which we pivot/aggregate // any columns which are not pivoted/aggregated on are added to the GROUP BY clause @@ -533,6 +566,32 @@ unique_ptr Binder::BindPivot(PivotRef &ref, vector Binder::BindPivot(PivotRef &ref, vector(context); + auto pivot_limit = Settings::Get(context); if (total_pivots >= pivot_limit) { throw BinderException(ref, "Pivot column limit of %llu exceeded. Use SET pivot_limit=X to increase the limit.", pivot_limit); @@ -603,7 +662,7 @@ unique_ptr Binder::BindPivot(PivotRef &ref, vector filtered aggregates are faster when there are FEW pivot values // -> LIST is faster when there are MANY pivot values // we switch dynamically based on the number of pivots to compute - auto pivot_filter_threshold = DBConfig::GetSetting(context); + auto pivot_filter_threshold = Settings::Get(context); if (pivot_values.size() <= pivot_filter_threshold) { // use a set of filtered aggregates pivot_node = @@ -640,6 +699,17 @@ struct UnpivotEntry { void Binder::ExtractUnpivotEntries(Binder &child_binder, PivotColumnEntry &entry, vector &unpivot_entries) { + // Try to bind the entry expression as values + try { + auto expr_copy = entry.expr->Copy(); + BindPivotInList(expr_copy, entry.values, child_binder); + // successfully bound as values - clear the expression + entry.expr = nullptr; + } catch (...) { + // ignore binder exceptions here - we fall back to expression mode + entry.values.clear(); + } + if (!entry.expr) { // pivot entry without an expression - generate one UnpivotEntry unpivot_entry; diff --git a/src/duckdb/src/planner/binder/tableref/bind_showref.cpp b/src/duckdb/src/planner/binder/tableref/bind_showref.cpp index d2d91c3af..3b68d6bd8 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_showref.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_showref.cpp @@ -156,6 +156,16 @@ BoundStatement Binder::BindShowTable(ShowRef &ref) { string sql; if (lname == "\"databases\"") { sql = PragmaShowDatabases(); + } else if (lname == "\"schemas\"") { + sql = "SELECT " + " schema.database_name, " + " schema.schema_name, " + " ((select current_schema() = schema.schema_name) " + " and (select current_database() = schema.database_name)) \"current\" " + "FROM duckdb_schemas() schema " + "JOIN duckdb_databases dbs USING (database_oid) " + "WHERE dbs.internal = false " + "ORDER BY all;"; } else if (lname == "\"tables\"") { sql = PragmaShowTables(); } else if (ref.show_type == ShowType::SHOW_FROM) { diff --git a/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp b/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp index 528478c58..4d2a47629 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp @@ -193,7 +193,7 @@ BoundStatement Binder::BindTableFunctionInternal(TableFunction &table_function, vector return_names; auto constexpr ordinality_name = "ordinality"; string ordinality_column_name = ordinality_name; - idx_t ordinality_column_id; + optional_idx ordinality_column_id; if (table_function.bind || table_function.bind_replace || table_function.bind_operator) { TableFunctionBindInput bind_input(parameters, named_parameters, input_table_types, input_table_names, table_function.function_info.get(), this, table_function, ref); diff --git a/src/duckdb/src/planner/collation_binding.cpp b/src/duckdb/src/planner/collation_binding.cpp index dd371bbc4..ea70f0194 100644 --- a/src/duckdb/src/planner/collation_binding.cpp +++ b/src/duckdb/src/planner/collation_binding.cpp @@ -20,7 +20,7 @@ bool PushVarcharCollation(ClientContext &context, unique_ptr &source auto str_collation = StringType::GetCollation(sql_type); string collation; if (str_collation.empty()) { - collation = DBConfig::GetSetting(context); + collation = Settings::Get(context); } else { collation = str_collation; } diff --git a/src/duckdb/src/planner/expression/bound_cast_expression.cpp b/src/duckdb/src/planner/expression/bound_cast_expression.cpp index e2efdfa2e..1de7ee2b1 100644 --- a/src/duckdb/src/planner/expression/bound_cast_expression.cpp +++ b/src/duckdb/src/planner/expression/bound_cast_expression.cpp @@ -6,6 +6,7 @@ #include "duckdb/function/cast_rules.hpp" #include "duckdb/function/cast/cast_function_set.hpp" #include "duckdb/main/config.hpp" +#include "duckdb/planner/expression_binder.hpp" namespace duckdb { diff --git a/src/duckdb/src/planner/expression_binder.cpp b/src/duckdb/src/planner/expression_binder.cpp index de1019753..c2cc9bff5 100644 --- a/src/duckdb/src/planner/expression_binder.cpp +++ b/src/duckdb/src/planner/expression_binder.cpp @@ -7,6 +7,7 @@ #include "duckdb/planner/expression_iterator.hpp" #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/main/client_config.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/common/string_util.hpp" namespace duckdb { @@ -47,11 +48,11 @@ void ExpressionBinder::InitializeStackCheck() { StackChecker ExpressionBinder::StackCheck(const ParsedExpression &expr, idx_t extra_stack) { D_ASSERT(stack_depth != DConstants::INVALID_INDEX); - auto &options = ClientConfig::GetConfig(context); - if (stack_depth + extra_stack >= options.max_expression_depth) { + auto max_expression_depth = Settings::Get(context); + if (stack_depth + extra_stack >= max_expression_depth) { throw BinderException("Max expression depth limit of %lld exceeded. Use \"SET max_expression_depth TO x\" to " "increase the maximum expression depth.", - options.max_expression_depth); + max_expression_depth); } return StackChecker(*this, extra_stack); } @@ -79,6 +80,8 @@ BindResult ExpressionBinder::BindExpression(unique_ptr &expr, return BindExpression(expr_ref.Cast(), depth); case ExpressionClass::CONSTANT: return BindExpression(expr_ref.Cast(), depth); + case ExpressionClass::TYPE: + return BindExpression(expr_ref.Cast(), depth); case ExpressionClass::FUNCTION: { auto &function = expr_ref.Cast(); if (IsUnnestFunction(function.function_name)) { diff --git a/src/duckdb/src/planner/expression_binder/having_binder.cpp b/src/duckdb/src/planner/expression_binder/having_binder.cpp index ab0f11af5..c6a7ad3af 100644 --- a/src/duckdb/src/planner/expression_binder/having_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/having_binder.cpp @@ -15,6 +15,10 @@ HavingBinder::HavingBinder(Binder &binder, ClientContext &context, BoundSelectNo target_type = LogicalType(LogicalTypeId::BOOLEAN); } +bool HavingBinder::DoesColumnAliasExist(const ColumnRefExpression &colref) { + return column_alias_binder.DoesColumnAliasExist(colref); +} + BindResult HavingBinder::BindLambdaReference(LambdaRefExpression &expr, idx_t depth) { D_ASSERT(lambda_bindings && expr.lambda_idx < lambda_bindings->size()); auto &lambda_ref = expr.Cast(); diff --git a/src/duckdb/src/planner/expression_binder/index_binder.cpp b/src/duckdb/src/planner/expression_binder/index_binder.cpp index 17707173c..d44bcfb09 100644 --- a/src/duckdb/src/planner/expression_binder/index_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/index_binder.cpp @@ -41,7 +41,7 @@ unique_ptr IndexBinder::BindIndex(const UnboundIndex &unbound_index) unbound_expressions.push_back(Bind(copy)); } - CreateIndexInput input(unbound_index.table_io_manager, unbound_index.db, create_info.constraint_type, + CreateIndexInput input(context, unbound_index.table_io_manager, unbound_index.db, create_info.constraint_type, create_info.index_name, create_info.column_ids, unbound_expressions, storage_info, create_info.options); diff --git a/src/duckdb/src/planner/expression_binder/order_binder.cpp b/src/duckdb/src/planner/expression_binder/order_binder.cpp index 3923129fb..1ad8582eb 100644 --- a/src/duckdb/src/planner/expression_binder/order_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/order_binder.cpp @@ -61,7 +61,7 @@ optional_idx OrderBinder::TryGetProjectionReference(ParsedExpression &expr) cons // ORDER BY has no effect // this is disabled by default (matching Postgres) - but we can control this with a setting auto order_by_non_integer_literal = - DBConfig::GetSetting(binders[0].get().context); + Settings::Get(binders[0].get().context); if (!order_by_non_integer_literal) { throw BinderException(expr, "%s non-integer literal has no effect.\n* SET " @@ -83,11 +83,28 @@ optional_idx OrderBinder::TryGetProjectionReference(ParsedExpression &expr) cons string alias_name = colref.column_names.back(); // check the alias list auto entry = bind_state.alias_map.find(alias_name); - if (entry == bind_state.alias_map.end()) { - break; + if (entry != bind_state.alias_map.end()) { + // this is an alias - return the index + return entry->second; } - // this is an alias - return the index - return entry->second; + // check the expression list + vector matching_columns; + for (idx_t i = 0; i < bind_state.original_expressions.size(); i++) { + if (bind_state.original_expressions[i]->type != ExpressionType::COLUMN_REF) { + continue; + } + auto &colref = bind_state.original_expressions[i]->Cast(); + if (colref.HasAlias()) { + continue; + } + if (colref.GetColumnName() == alias_name) { + matching_columns.push_back(i); + } + } + if (matching_columns.size() == 1) { + return matching_columns[0]; + } + break; } case ExpressionClass::POSITIONAL_REFERENCE: { auto &posref = expr.Cast(); diff --git a/src/duckdb/src/planner/expression_binder/table_function_binder.cpp b/src/duckdb/src/planner/expression_binder/table_function_binder.cpp index 16b612cd6..f653a129d 100644 --- a/src/duckdb/src/planner/expression_binder/table_function_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/table_function_binder.cpp @@ -51,9 +51,11 @@ BindResult TableFunctionBinder::BindColumnReference(unique_ptr } } - auto value_function = ExpressionBinder::GetSQLValueFunction(column_names.back()); - if (value_function) { - return BindExpression(value_function, depth, root_expression); + if (accept_sql_value_functions) { + auto value_function = ExpressionBinder::GetSQLValueFunction(column_names.back()); + if (value_function) { + return BindExpression(value_function, depth, root_expression); + } } auto result = BindCorrelatedColumns(expr_ptr, ErrorData("error")); diff --git a/src/duckdb/src/planner/operator/logical_delete.cpp b/src/duckdb/src/planner/operator/logical_delete.cpp index d82c3bfd8..de3080f02 100644 --- a/src/duckdb/src/planner/operator/logical_delete.cpp +++ b/src/duckdb/src/planner/operator/logical_delete.cpp @@ -3,6 +3,7 @@ #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/main/config.hpp" #include "duckdb/parser/parsed_data/create_table_info.hpp" +#include "duckdb/planner/binder.hpp" namespace duckdb { diff --git a/src/duckdb/src/planner/operator/logical_extension_operator.cpp b/src/duckdb/src/planner/operator/logical_extension_operator.cpp index 2e0cb6d15..98fea77ed 100644 --- a/src/duckdb/src/planner/operator/logical_extension_operator.cpp +++ b/src/duckdb/src/planner/operator/logical_extension_operator.cpp @@ -1,8 +1,8 @@ #include "duckdb/planner/operator/logical_extension_operator.hpp" #include "duckdb/execution/column_binding_resolver.hpp" -#include "duckdb/main/config.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" +#include "duckdb/planner/operator_extension.hpp" namespace duckdb { @@ -26,9 +26,9 @@ void LogicalExtensionOperator::Serialize(Serializer &serializer) const { } unique_ptr LogicalExtensionOperator::Deserialize(Deserializer &deserializer) { - auto &config = DBConfig::GetConfig(deserializer.Get()); + auto &context = deserializer.Get(); auto extension_name = deserializer.ReadProperty(200, "extension_name"); - for (auto &extension : config.operator_extensions) { + for (auto &extension : OperatorExtension::Iterate(context)) { if (extension->GetName() == extension_name) { return extension->Deserialize(deserializer); } diff --git a/src/duckdb/src/planner/operator/logical_get.cpp b/src/duckdb/src/planner/operator/logical_get.cpp index 25ea5b586..fe7088adf 100644 --- a/src/duckdb/src/planner/operator/logical_get.cpp +++ b/src/duckdb/src/planner/operator/logical_get.cpp @@ -228,6 +228,14 @@ idx_t LogicalGet::EstimateCardinality(ClientContext &context) { return 1; } +void LogicalGet::SetScanOrder(unique_ptr options) { + if (!function.set_scan_order) { + throw InternalException("LogicalGet::SetScanOrder called but function does not have scan order defined"); + } + row_group_order_options = make_uniq(*options); + function.set_scan_order(std::move(options), bind_data.get()); +} + void LogicalGet::Serialize(Serializer &serializer) const { LogicalOperator::Serialize(serializer); serializer.WriteProperty(200, "table_index", table_index); @@ -249,6 +257,8 @@ void LogicalGet::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault(211, "column_indexes", column_ids); serializer.WritePropertyWithDefault(212, "extra_info", extra_info, ExtraOperatorInfo {}); serializer.WritePropertyWithDefault(213, "ordinality_idx", ordinality_idx); + serializer.WritePropertyWithDefault>(214, "row_group_order_options", + row_group_order_options); } unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) { @@ -279,6 +289,8 @@ unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) deserializer.ReadPropertyWithDefault(211, "column_indexes", result->column_ids); result->extra_info = deserializer.ReadPropertyWithExplicitDefault(212, "extra_info", {}); deserializer.ReadPropertyWithDefault(213, "ordinality_idx", result->ordinality_idx); + auto row_group_order_options = + deserializer.ReadPropertyWithDefault>(214, "row_group_order_options"); if (!legacy_column_ids.empty()) { if (!result->column_ids.empty()) { throw SerializationException( @@ -335,6 +347,9 @@ unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) } result->virtual_columns = std::move(virtual_columns); result->bind_data = std::move(bind_data); + if (row_group_order_options) { + result->SetScanOrder(std::move(row_group_order_options)); + } return std::move(result); } diff --git a/src/duckdb/src/planner/operator/logical_insert.cpp b/src/duckdb/src/planner/operator/logical_insert.cpp index bab6820fe..52c5d25d1 100644 --- a/src/duckdb/src/planner/operator/logical_insert.cpp +++ b/src/duckdb/src/planner/operator/logical_insert.cpp @@ -3,6 +3,7 @@ #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/main/config.hpp" #include "duckdb/parser/parsed_data/create_table_info.hpp" +#include "duckdb/planner/binder.hpp" namespace duckdb { diff --git a/src/duckdb/src/planner/operator/logical_merge_into.cpp b/src/duckdb/src/planner/operator/logical_merge_into.cpp index fa99f69ab..cd74905dd 100644 --- a/src/duckdb/src/planner/operator/logical_merge_into.cpp +++ b/src/duckdb/src/planner/operator/logical_merge_into.cpp @@ -1,6 +1,8 @@ #include "duckdb/planner/operator/logical_merge_into.hpp" + #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/parser/parsed_data/create_table_info.hpp" +#include "duckdb/planner/binder.hpp" namespace duckdb { diff --git a/src/duckdb/src/planner/operator/logical_update.cpp b/src/duckdb/src/planner/operator/logical_update.cpp index 386264478..b2de4d12d 100644 --- a/src/duckdb/src/planner/operator/logical_update.cpp +++ b/src/duckdb/src/planner/operator/logical_update.cpp @@ -1,7 +1,9 @@ #include "duckdb/planner/operator/logical_update.hpp" + #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" -#include "duckdb/parser/parsed_data/create_table_info.hpp" #include "duckdb/main/config.hpp" +#include "duckdb/parser/parsed_data/create_table_info.hpp" +#include "duckdb/planner/binder.hpp" namespace duckdb { diff --git a/src/duckdb/src/planner/operator/logical_vacuum.cpp b/src/duckdb/src/planner/operator/logical_vacuum.cpp index ce4a76951..734ae8ea3 100644 --- a/src/duckdb/src/planner/operator/logical_vacuum.cpp +++ b/src/duckdb/src/planner/operator/logical_vacuum.cpp @@ -1,9 +1,11 @@ #include "duckdb/planner/operator/logical_vacuum.hpp" -#include "duckdb/planner/operator/logical_get.hpp" + #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" -#include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" +#include "duckdb/common/serializer/serializer.hpp" #include "duckdb/parser/parsed_data/vacuum_info.hpp" +#include "duckdb/planner/binder.hpp" +#include "duckdb/planner/operator/logical_get.hpp" namespace duckdb { diff --git a/src/duckdb/src/planner/planner.cpp b/src/duckdb/src/planner/planner.cpp index e6794dcfc..7f5caba77 100644 --- a/src/duckdb/src/planner/planner.cpp +++ b/src/duckdb/src/planner/planner.cpp @@ -9,6 +9,7 @@ #include "duckdb/main/database.hpp" #include "duckdb/main/prepared_statement_data.hpp" #include "duckdb/main/query_profiler.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" #include "duckdb/transaction/meta_transaction.hpp" @@ -16,6 +17,8 @@ #include "duckdb/main/attached_database.hpp" #include "duckdb/parser/statement/multi_statement.hpp" #include "duckdb/planner/subquery/flatten_dependent_join.hpp" +#include "duckdb/planner/operator_extension.hpp" +#include "duckdb/planner/planner_extension.hpp" namespace duckdb { @@ -31,6 +34,15 @@ static void CheckTreeDepth(const LogicalOperator &op, idx_t max_depth, idx_t dep } } +static void RunPostBindExtensions(ClientContext &context, Binder &binder, BoundStatement &statement) { + for (auto &planner_extension : PlannerExtension::Iterate(context)) { + if (planner_extension.post_bind_function) { + PlannerExtensionInput input {context, binder, planner_extension.planner_info.get()}; + planner_extension.post_bind_function(input, statement); + } + } +} + void Planner::CreatePlan(SQLStatement &statement) { auto &profiler = QueryProfiler::Get(context); auto parameter_count = statement.named_param_map.size(); @@ -45,6 +57,8 @@ void Planner::CreatePlan(SQLStatement &statement) { auto bound_statement = binder->Bind(statement); profiler.EndPhase(); + RunPostBindExtensions(context, *binder, bound_statement); + this->names = bound_statement.names; this->types = bound_statement.types; this->plan = std::move(bound_statement.plan); @@ -58,11 +72,12 @@ void Planner::CreatePlan(SQLStatement &statement) { parameters_resolved = false; } else if (error.Type() != ExceptionType::INVALID) { // different exception type - try operator_extensions - auto &config = DBConfig::GetConfig(context); - for (auto &extension_op : config.operator_extensions) { + for (auto &extension_op : OperatorExtension::Iterate(context)) { auto bound_statement = extension_op->Bind(context, *this->binder, extension_op->operator_info.get(), statement); if (bound_statement.plan != nullptr) { + RunPostBindExtensions(context, *this->binder, bound_statement); + this->names = bound_statement.names; this->types = bound_statement.types; this->plan = std::move(bound_statement.plan); @@ -77,7 +92,7 @@ void Planner::CreatePlan(SQLStatement &statement) { } } if (this->plan) { - auto max_tree_depth = ClientConfig::GetConfig(context).max_expression_depth; + auto max_tree_depth = Settings::Get(context); CheckTreeDepth(*plan, max_tree_depth); this->plan = FlattenDependentJoins::DecorrelateIndependent(*this->binder, std::move(this->plan)); diff --git a/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp b/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp index 23dd23ec4..f6c0315c5 100644 --- a/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp +++ b/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp @@ -618,19 +618,20 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoinInternal } // both sides have correlation // turn into an inner join + // correctly use left child's delim_offset so execute left child as the last one auto join = make_uniq(JoinType::INNER); - plan->children[0] = - PushDownDependentJoinInternal(std::move(plan->children[0]), parent_propagate_null_values, lateral_depth); - auto left_binding = this->base_binding; plan->children[1] = PushDownDependentJoinInternal(std::move(plan->children[1]), parent_propagate_null_values, lateral_depth); + auto right_binding = this->base_binding; + plan->children[0] = + PushDownDependentJoinInternal(std::move(plan->children[0]), parent_propagate_null_values, lateral_depth); // add the correlated columns to the join conditions for (idx_t i = 0; i < correlated_columns.size(); i++) { JoinCondition cond; cond.left = make_uniq( - correlated_columns[i].type, ColumnBinding(left_binding.table_index, left_binding.column_index + i)); - cond.right = make_uniq( correlated_columns[i].type, ColumnBinding(base_binding.table_index, base_binding.column_index + i)); + cond.right = make_uniq( + correlated_columns[i].type, ColumnBinding(right_binding.table_index, right_binding.column_index + i)); cond.comparison = ExpressionType::COMPARE_NOT_DISTINCT_FROM; join->conditions.push_back(std::move(cond)); } diff --git a/src/duckdb/src/storage/buffer/block_handle.cpp b/src/duckdb/src/storage/buffer/block_handle.cpp index 91c98d4b4..5abfb64e8 100644 --- a/src/duckdb/src/storage/buffer/block_handle.cpp +++ b/src/duckdb/src/storage/buffer/block_handle.cpp @@ -10,222 +10,229 @@ namespace duckdb { -BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, MemoryTag tag) - : block_manager(block_manager), readers(0), block_id(block_id_p), tag(tag), buffer_type(FileBufferType::BLOCK), - buffer(nullptr), eviction_seq_num(0), destroy_buffer_upon(DestroyBufferUpon::BLOCK), - memory_charge(tag, block_manager.buffer_manager.GetBufferPool()), unswizzled(nullptr), +BlockMemory::BlockMemory(BufferManager &buffer_manager, block_id_t block_id_p, MemoryTag tag_p, + idx_t block_alloc_size_p) + : buffer_manager(buffer_manager), block_id(block_id_p), state(BlockState::BLOCK_UNLOADED), readers(0), tag(tag_p), + buffer_type(FileBufferType::BLOCK), buffer(nullptr), eviction_seq_num(0), lru_timestamp_msec(), + destroy_buffer_upon(DestroyBufferUpon::BLOCK), memory_usage(block_alloc_size_p), + memory_charge(tag, buffer_manager.GetBufferPool()), unswizzled(nullptr), eviction_queue_idx(DConstants::INVALID_INDEX) { - eviction_seq_num = 0; - state = BlockState::BLOCK_UNLOADED; - memory_usage = block_manager.GetBlockAllocSize(); } -BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, MemoryTag tag, - unique_ptr buffer_p, DestroyBufferUpon destroy_buffer_upon_p, idx_t block_size, +BlockMemory::BlockMemory(BufferManager &buffer_manager, block_id_t block_id_p, MemoryTag tag_p, + unique_ptr buffer_p, DestroyBufferUpon destroy_buffer_upon_p, idx_t size_p, BufferPoolReservation &&reservation) - : block_manager(block_manager), readers(0), block_id(block_id_p), tag(tag), buffer_type(buffer_p->GetBufferType()), - eviction_seq_num(0), destroy_buffer_upon(destroy_buffer_upon_p), - memory_charge(tag, block_manager.buffer_manager.GetBufferPool()), unswizzled(nullptr), + : buffer_manager(buffer_manager), block_id(block_id_p), state(BlockState::BLOCK_LOADED), readers(0), tag(tag_p), + buffer_type(buffer_p->GetBufferType()), buffer(std::move(buffer_p)), eviction_seq_num(0), lru_timestamp_msec(), + destroy_buffer_upon(destroy_buffer_upon_p), memory_usage(size_p), + memory_charge(tag, buffer_manager.GetBufferPool()), unswizzled(nullptr), eviction_queue_idx(DConstants::INVALID_INDEX) { - buffer = std::move(buffer_p); - state = BlockState::BLOCK_LOADED; - memory_usage = block_size; - memory_charge = std::move(reservation); + memory_charge = std::move(reservation); // Moved to constructor body due to tidy check. } -BlockHandle::~BlockHandle() { // NOLINT: allow internal exceptions - // being destroyed, so any unswizzled pointers are just binary junk now. - unswizzled = nullptr; - D_ASSERT(!buffer || buffer->GetBufferType() == buffer_type); - if (buffer && buffer_type != FileBufferType::TINY_BUFFER) { - // we kill the latest version in the eviction queue - auto &buffer_manager = block_manager.buffer_manager; - buffer_manager.GetBufferPool().IncrementDeadNodes(*this); +BlockMemory::~BlockMemory() { // NOLINT: allow internal exceptions + // The block memory is being destroyed, meaning that any unswizzled pointers are now binary junk. + SetSwizzling(nullptr); + D_ASSERT(!GetBuffer() || GetBuffer()->GetBufferType() == GetBufferType()); + if (GetBuffer() && GetBufferType() != FileBufferType::TINY_BUFFER) { + // Kill the latest version in the eviction queue. + GetBufferManager().GetBufferPool().IncrementDeadNodes(*this); } - // no references remain to this block: erase - if (buffer && state == BlockState::BLOCK_LOADED) { - D_ASSERT(memory_charge.size > 0); - // the block is still loaded in memory: erase it - buffer.reset(); - memory_charge.Resize(0); + // Erase the block memory, if it is still loaded. + if (GetBuffer() && GetState() == BlockState::BLOCK_LOADED) { + D_ASSERT(GetMemoryCharge().size > 0); + SetBuffer(nullptr); + GetMemoryCharge().Resize(0); } else { - D_ASSERT(memory_charge.size == 0); - } - try { - block_manager.UnregisterBlock(*this); - } catch (...) { + D_ASSERT(GetMemoryCharge().size == 0); } -} -unique_ptr AllocateBlock(BlockManager &block_manager, unique_ptr reusable_buffer, - block_id_t block_id) { - if (reusable_buffer && reusable_buffer->GetHeaderSize() == block_manager.GetBlockHeaderSize()) { - // re-usable buffer: re-use it - if (reusable_buffer->GetBufferType() == FileBufferType::BLOCK) { - // we can reuse the buffer entirely - auto &block = reinterpret_cast(*reusable_buffer); - block.id = block_id; - return unique_ptr_cast(std::move(reusable_buffer)); + try { + if (BlockId() >= MAXIMUM_BLOCK) { + // The memory buffer lives in memory. + // Thus, it could've been offloaded to disk, and we should remove the file. + GetBufferManager().DeleteTemporaryFile(*this); } - auto block = block_manager.CreateBlock(block_id, reusable_buffer.get()); - reusable_buffer.reset(); - return block; - } else { - // no re-usable buffer: allocate a new block - return block_manager.CreateBlock(block_id, nullptr); + } catch (...) { // NOLINT + // FIXME: log silent exceptions. } } -void BlockHandle::ChangeMemoryUsage(BlockLock &l, int64_t delta) { +void BlockMemory::ChangeMemoryUsage(BlockLock &l, int64_t delta) { VerifyMutex(l); - + // FIXME: Too clever ATM. The crux here is that the unsigned overflow is defined. + // FIXME: It overflows twice to lead to the correct subtraction. D_ASSERT(delta < 0); memory_usage += static_cast(delta); - memory_charge.Resize(memory_usage); + GetMemoryCharge().Resize(GetMemoryUsage()); } -unique_ptr &BlockHandle::GetBuffer(BlockLock &l) { +void BlockMemory::ConvertToPersistent(BlockLock &l, BlockHandle &new_block, unique_ptr new_buffer) { VerifyMutex(l); - return buffer; -} - -void BlockHandle::VerifyMutex(BlockLock &l) const { - D_ASSERT(l.owns_lock()); - D_ASSERT(l.mutex() == &lock); -} -BufferPoolReservation &BlockHandle::GetMemoryCharge(BlockLock &l) { - VerifyMutex(l); - return memory_charge; -} + auto &new_block_memory = new_block.GetMemory(); + D_ASSERT(GetMemoryTag() == memory_charge.tag); + if (GetMemoryTag() != new_block_memory.GetMemoryTag()) { + const auto memory_charge_size = memory_charge.size; + memory_charge.Resize(0); + memory_charge.tag = new_block_memory.tag; + memory_charge.Resize(memory_charge_size); + } -void BlockHandle::MergeMemoryReservation(BlockLock &l, BufferPoolReservation reservation) { - VerifyMutex(l); - memory_charge.Merge(std::move(reservation)); -} + // Move the old block memory to the new block memory. + new_block_memory.SetState(BlockState::BLOCK_LOADED); + new_block_memory.GetBuffer() = std::move(new_buffer); + new_block_memory.memory_usage = memory_usage.load(); + new_block_memory.memory_charge = std::move(memory_charge); -void BlockHandle::ResizeMemory(BlockLock &l, idx_t alloc_size) { - VerifyMutex(l); - memory_charge.Resize(alloc_size); + // Clear the buffered data of this block. + buffer.reset(); + SetState(BlockState::BLOCK_UNLOADED); + memory_usage = 0; } -void BlockHandle::ResizeBuffer(BlockLock &l, idx_t block_size, int64_t memory_delta) { +void BlockMemory::ResizeBuffer(BlockLock &l, idx_t block_size, idx_t block_header_size, int64_t memory_delta) { + // Resize and adjust the current memory. VerifyMutex(l); - D_ASSERT(buffer); - // resize and adjust current memory - buffer->Resize(block_size, block_manager); - memory_usage = NumericCast(NumericCast(memory_usage.load()) + memory_delta); + buffer->Resize(block_size, block_header_size); + const auto new_memory_usage = NumericCast(NumericCast(memory_usage.load()) + memory_delta); + memory_usage = new_memory_usage; D_ASSERT(memory_usage == buffer->AllocSize()); } -BufferHandle BlockHandle::LoadFromBuffer(BlockLock &l, data_ptr_t data, unique_ptr reusable_buffer, - BufferPoolReservation reservation) { - VerifyMutex(l); - - D_ASSERT(state != BlockState::BLOCK_LOADED); - D_ASSERT(readers == 0); - // copy over the data into the block from the file buffer - auto block = AllocateBlock(block_manager, std::move(reusable_buffer), block_id); - memcpy(block->InternalBuffer(), data, block->AllocSize()); - buffer = std::move(block); - state = BlockState::BLOCK_LOADED; - readers = 1; - memory_charge = std::move(reservation); - return BufferHandle(shared_from_this(), buffer.get()); -} - -BufferHandle BlockHandle::Load(QueryContext context, unique_ptr reusable_buffer) { - if (state == BlockState::BLOCK_LOADED) { - // already loaded - D_ASSERT(buffer); - ++readers; - return BufferHandle(shared_from_this(), buffer.get()); +bool BlockMemory::CanUnload() const { + if (GetState() == BlockState::BLOCK_UNLOADED) { + // The block has already been unloaded. + return false; } - - if (block_id < MAXIMUM_BLOCK) { - auto block = AllocateBlock(block_manager, std::move(reusable_buffer), block_id); - block_manager.Read(context, *block); - buffer = std::move(block); - } else { - if (MustWriteToTemporaryFile()) { - buffer = block_manager.buffer_manager.ReadTemporaryBuffer(QueryContext(), tag, *this, - std::move(reusable_buffer)); - } else { - return BufferHandle(); // Destroyed upon unpin/evict, so there is no temp buffer to read - } + if (GetReaders() > 0) { + // There are active readers. + return false; + } + if (BlockId() >= MAXIMUM_BLOCK && MustWriteToTemporaryFile() && !GetBufferManager().HasTemporaryDirectory()) { + // The block memory cannot be destroyed upon eviction/unpinning. + // In order to unload this block we need to write it to a temporary buffer. + // However, no temporary directory is specified, hence, we cannot unload. + return false; } - state = BlockState::BLOCK_LOADED; - readers = 1; - return BufferHandle(shared_from_this(), buffer.get()); + return true; } -unique_ptr BlockHandle::UnloadAndTakeBlock(BlockLock &lock) { - VerifyMutex(lock); +unique_ptr BlockMemory::UnloadAndTakeBlock(BlockLock &l) { + VerifyMutex(l); - if (state == BlockState::BLOCK_UNLOADED) { - // already unloaded: nothing to do + if (GetState() == BlockState::BLOCK_UNLOADED) { + // The block was already unloaded: nothing to do. return nullptr; } - D_ASSERT(!unswizzled); + D_ASSERT(IsSwizzled()); D_ASSERT(CanUnload()); - if (block_id >= MAXIMUM_BLOCK && MustWriteToTemporaryFile()) { - // temporary block that cannot be destroyed upon evict/unpin: write to temporary file - block_manager.buffer_manager.WriteTemporaryBuffer(tag, block_id, *buffer); + if (BlockId() >= MAXIMUM_BLOCK && MustWriteToTemporaryFile()) { + // This is a temporary block that cannot be destroyed upon evict/unpin. + // Thus, we write to it to a temporary file. + buffer_manager.WriteTemporaryBuffer(GetMemoryTag(), BlockId(), *GetBuffer()); } memory_charge.Resize(0); - state = BlockState::BLOCK_UNLOADED; - return std::move(buffer); + SetState(BlockState::BLOCK_UNLOADED); + return std::move(GetBuffer()); } -void BlockHandle::Unload(BlockLock &lock) { - auto block = UnloadAndTakeBlock(lock); +void BlockMemory::Unload(BlockLock &l) { + auto block = UnloadAndTakeBlock(l); block.reset(); } -bool BlockHandle::CanUnload() const { - if (state == BlockState::BLOCK_UNLOADED) { - // already unloaded - return false; +BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, MemoryTag tag_p) + : block_manager(block_manager), block_alloc_size(block_manager.GetBlockAllocSize()), + block_header_size(block_manager.GetBlockHeaderSize()), block_id(block_id_p), + memory_p(make_shared_ptr(block_manager.GetBufferManager(), block_id_p, tag_p, block_alloc_size)), + memory(*memory_p) { +} + +BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, MemoryTag tag_p, + unique_ptr buffer_p, DestroyBufferUpon destroy_buffer_upon_p, idx_t size_p, + BufferPoolReservation &&reservation) + : block_manager(block_manager), block_alloc_size(block_manager.GetBlockAllocSize()), + block_header_size(block_manager.GetBlockHeaderSize()), block_id(block_id_p), + memory_p(make_shared_ptr(block_manager.GetBufferManager(), block_id_p, tag_p, std::move(buffer_p), + destroy_buffer_upon_p, size_p, std::move(reservation))), + memory(*memory_p) { +} + +BlockHandle::~BlockHandle() { // NOLINT: allow internal exceptions + // Early-out for temporary blocks. + if (block_id >= MAXIMUM_BLOCK) { + return; } - if (readers > 0) { - // there are active readers - return false; + try { + block_manager.UnregisterPersistentBlock(*this); + } catch (...) { // NOLINT + // FIXME: log silent exceptions. } - if (block_id >= MAXIMUM_BLOCK && MustWriteToTemporaryFile() && - !block_manager.buffer_manager.HasTemporaryDirectory()) { - // this block cannot be destroyed upon evict/unpin - // in order to unload this block we need to write it to a temporary buffer - // however, no temporary directory is specified! - // hence we cannot unload the block - return false; +} + +unique_ptr AllocateBlock(BlockManager &block_manager, unique_ptr reusable_buffer, + block_id_t block_id) { + if (reusable_buffer && reusable_buffer->GetHeaderSize() == block_manager.GetBlockHeaderSize()) { + // Reusable buffer: reuse it. + if (reusable_buffer->GetBufferType() == FileBufferType::BLOCK) { + // Reuse the entire buffer. + auto &block = reinterpret_cast(*reusable_buffer); + block.id = block_id; + return unique_ptr_cast(std::move(reusable_buffer)); + } + auto block = block_manager.CreateBlock(block_id, reusable_buffer.get()); + reusable_buffer.reset(); + return block; } - return true; + + // Not a reusable buffer: allocate a new block. + return block_manager.CreateBlock(block_id, nullptr); } -void BlockHandle::ConvertToPersistent(BlockLock &l, BlockHandle &new_block, unique_ptr new_buffer) { - VerifyMutex(l); +BufferHandle BlockHandle::LoadFromBuffer(BlockLock &l, data_ptr_t data, unique_ptr reusable_buffer, + BufferPoolReservation reservation) { + memory.VerifyMutex(l); + // Copy the data of the file buffer into the block. + D_ASSERT(memory.GetState() != BlockState::BLOCK_LOADED); + D_ASSERT(memory.GetReaders() == 0); + auto block = AllocateBlock(block_manager, std::move(reusable_buffer), block_id); + memcpy(block->InternalBuffer(), data, block->AllocSize()); + memory.GetBuffer() = std::move(block); + memory.SetState(BlockState::BLOCK_LOADED); + memory.SetReaders(1); + memory.GetMemoryCharge() = std::move(reservation); + return BufferHandle(shared_from_this(), memory.GetBuffer()); +} - D_ASSERT(tag == memory_charge.tag); - if (tag != new_block.tag) { - const auto memory_charge_size = memory_charge.size; - memory_charge.Resize(0); - memory_charge.tag = new_block.tag; - memory_charge.Resize(memory_charge_size); +BufferHandle BlockHandle::Load(QueryContext context, unique_ptr reusable_buffer) { + if (memory.GetState() == BlockState::BLOCK_LOADED) { + // The block has already been loaded. + D_ASSERT(memory.GetBuffer()); + memory.IncrementReaders(); + return BufferHandle(shared_from_this(), memory.GetBuffer()); } - // move the data from the old block into data for the new block - new_block.state = BlockState::BLOCK_LOADED; - new_block.buffer = std::move(new_buffer); - new_block.memory_usage = memory_usage.load(); - new_block.memory_charge = std::move(memory_charge); - - // clear out the buffer data from this block - buffer.reset(); - state = BlockState::BLOCK_UNLOADED; - memory_usage = 0; + if (BlockId() < MAXIMUM_BLOCK) { + auto block = AllocateBlock(block_manager, std::move(reusable_buffer), block_id); + block_manager.Read(context, *block); + memory.GetBuffer() = std::move(block); + } else { + if (!memory.MustWriteToTemporaryFile()) { + // The buffer was destroyed upon unpin/evict, so there is no temporary buffer to read. + return BufferHandle(); + } + auto &buffer_manager = memory.GetBufferManager(); + auto &buffer = memory.GetBuffer(); + buffer = buffer_manager.ReadTemporaryBuffer(QueryContext(), memory.GetMemoryTag(), *this, + std::move(reusable_buffer)); + } + memory.SetState(BlockState::BLOCK_LOADED); + memory.SetReaders(1); + return BufferHandle(shared_from_this(), memory.GetBuffer()); } } // namespace duckdb diff --git a/src/duckdb/src/storage/buffer/block_manager.cpp b/src/duckdb/src/storage/buffer/block_manager.cpp index 3f68d6265..e005a2aa8 100644 --- a/src/duckdb/src/storage/buffer/block_manager.cpp +++ b/src/duckdb/src/storage/buffer/block_manager.cpp @@ -22,12 +22,19 @@ bool BlockManager::BlockIsRegistered(block_id_t block_id) { return false; } // already exists: check if it hasn't expired yet - auto existing_ptr = entry->second.lock(); - if (existing_ptr) { - //! it hasn't! return it - return true; + return !entry->second.expired(); +} + +shared_ptr BlockManager::TryGetBlock(block_id_t block_id) { + lock_guard lock(blocks_lock); + // check if the block already exists + auto entry = blocks.find(block_id); + if (entry == blocks.end()) { + // the block does not exist + return nullptr; } - return false; + // the block exists - try to lock it + return entry->second.lock(); } shared_ptr BlockManager::RegisterBlock(block_id_t block_id) { @@ -54,24 +61,25 @@ shared_ptr BlockManager::ConvertToPersistent(QueryContext context, ConvertToPersistentMode mode) { // register a block with the new block id auto new_block = RegisterBlock(block_id); - D_ASSERT(new_block->GetState() == BlockState::BLOCK_UNLOADED); - D_ASSERT(new_block->Readers() == 0); + D_ASSERT(new_block->GetMemory().GetState() == BlockState::BLOCK_UNLOADED); + D_ASSERT(new_block->GetMemory().GetReaders() == 0); if (mode == ConvertToPersistentMode::THREAD_SAFE) { // safe mode - create a copy of the old block and operate on that // this ensures we don't modify the old block - which allows other concurrent operations on the old block to // continue - auto old_block_copy = buffer_manager.AllocateMemory(old_block->GetMemoryTag(), this, false); + auto old_block_copy = buffer_manager.AllocateMemory(old_block->GetMemory().GetMemoryTag(), this, false); auto copy_pin = buffer_manager.Pin(old_block_copy); memcpy(copy_pin.Ptr(), old_handle.Ptr(), GetBlockSize()); old_block = std::move(old_block_copy); old_handle = std::move(copy_pin); } - auto lock = old_block->GetLock(); - D_ASSERT(old_block->GetState() == BlockState::BLOCK_LOADED); - D_ASSERT(old_block->GetBuffer(lock)); - if (old_block->Readers() > 1) { + auto &old_block_memory = old_block->GetMemory(); + auto lock = old_block_memory.GetLock(); + D_ASSERT(old_block_memory.GetState() == BlockState::BLOCK_LOADED); + D_ASSERT(old_block_memory.GetBuffer(lock)); + if (old_block_memory.GetReaders() > 1) { throw InternalException( "BlockManager::ConvertToPersistent in destructive mode - cannot be called for block %d as old_block has " "multiple readers active", @@ -80,16 +88,16 @@ shared_ptr BlockManager::ConvertToPersistent(QueryContext context, // Temp buffers can be larger than the storage block size. // But persistent buffers cannot. - D_ASSERT(old_block->GetBuffer(lock)->AllocSize() <= GetBlockAllocSize()); + D_ASSERT(old_block_memory.GetBuffer(lock)->AllocSize() <= GetBlockAllocSize()); // convert the buffer to a block - auto converted_buffer = ConvertBlock(block_id, *old_block->GetBuffer(lock)); + auto converted_buffer = ConvertBlock(block_id, *old_block_memory.GetBuffer(lock)); // persist the new block to disk Write(context, *converted_buffer, block_id); // now convert the actual block - old_block->ConvertToPersistent(lock, *new_block, std::move(converted_buffer)); + old_block_memory.ConvertToPersistent(lock, *new_block, std::move(converted_buffer)); // destroy the old buffer lock.unlock(); @@ -119,17 +127,13 @@ void BlockManager::UnregisterBlock(block_id_t id) { blocks.erase(id); } -void BlockManager::UnregisterBlock(BlockHandle &block) { +void BlockManager::UnregisterPersistentBlock(BlockHandle &block) { if (in_destruction) { return; } auto id = block.BlockId(); - if (id >= MAXIMUM_BLOCK) { - // in-memory buffer: buffer could have been offloaded to disk: remove the file - buffer_manager.DeleteTemporaryFile(block); - } else { - UnregisterBlock(id); - } + D_ASSERT(id < MAXIMUM_BLOCK); + UnregisterBlock(id); } MetadataManager &BlockManager::GetMetadataManager() { diff --git a/src/duckdb/src/storage/buffer/buffer_handle.cpp b/src/duckdb/src/storage/buffer/buffer_handle.cpp index a0a5d20c9..44a59653f 100644 --- a/src/duckdb/src/storage/buffer/buffer_handle.cpp +++ b/src/duckdb/src/storage/buffer/buffer_handle.cpp @@ -34,7 +34,7 @@ void BufferHandle::Destroy() { if (!handle || !IsValid()) { return; } - handle->block_manager.buffer_manager.Unpin(handle); + handle->GetMemory().GetBufferManager().Unpin(handle); handle.reset(); node = nullptr; } diff --git a/src/duckdb/src/storage/buffer/buffer_pool.cpp b/src/duckdb/src/storage/buffer/buffer_pool.cpp index 9c13d4ccb..729bb89f7 100644 --- a/src/duckdb/src/storage/buffer/buffer_pool.cpp +++ b/src/duckdb/src/storage/buffer/buffer_pool.cpp @@ -1,10 +1,13 @@ #include "duckdb/storage/buffer/buffer_pool.hpp" #include "duckdb/common/exception.hpp" +#include "duckdb/common/thread.hpp" #include "duckdb/common/typedefs.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/parallel/concurrentqueue.hpp" #include "duckdb/parallel/task_scheduler.hpp" #include "duckdb/storage/block_allocator.hpp" +#include "duckdb/storage/object_cache.hpp" #include "duckdb/storage/temporary_memory_manager.hpp" namespace duckdb { @@ -36,31 +39,31 @@ static vector EvictionQueueTypeIdxToFileBufferTypes(const idx_t } } -BufferEvictionNode::BufferEvictionNode(weak_ptr handle_p, idx_t eviction_seq_num) - : handle(std::move(handle_p)), handle_sequence_number(eviction_seq_num) { - D_ASSERT(!handle.expired()); +BufferEvictionNode::BufferEvictionNode(weak_ptr block_memory_p, idx_t eviction_seq_num) + : memory_p(std::move(block_memory_p)), handle_sequence_number(eviction_seq_num) { + D_ASSERT(!memory_p.expired()); } -bool BufferEvictionNode::CanUnload(BlockHandle &handle_p) { - if (handle_sequence_number != handle_p.EvictionSequenceNumber()) { +bool BufferEvictionNode::CanUnload(BlockMemory &memory) { + if (handle_sequence_number != memory.GetEvictionSequenceNumber()) { // handle was used in between return false; } - return handle_p.CanUnload(); + return memory.CanUnload(); } -shared_ptr BufferEvictionNode::TryGetBlockHandle() { - auto handle_p = handle.lock(); - if (!handle_p) { - // BlockHandle has been destroyed +shared_ptr BufferEvictionNode::TryGetBlockMemory() { + auto shared_memory_p = memory_p.lock(); + if (!shared_memory_p) { + // The block memory has been destroyed. return nullptr; } - if (!CanUnload(*handle_p)) { - // handle was used in between + if (!CanUnload(*shared_memory_p)) { + // The memory handle was used in between. return nullptr; } - // this is the latest node in the queue with this handle - return handle_p; + // The node is the latest node in the queue with this memory. + return shared_memory_p; } typedef duckdb_moodycamel::ConcurrentQueue eviction_queue_t; @@ -68,7 +71,8 @@ typedef duckdb_moodycamel::ConcurrentQueue eviction_queue_t; struct EvictionQueue { public: explicit EvictionQueue(const vector &file_buffer_types_p) - : file_buffer_types(file_buffer_types_p), evict_queue_insertions(0), total_dead_nodes(0) { + : file_buffer_types(file_buffer_types_p), debug_eviction_queue_sleep(0), evict_queue_insertions(0), + total_dead_nodes(0) { } public: @@ -90,6 +94,9 @@ struct EvictionQueue { inline void DecrementDeadNodes() { total_dead_nodes--; } + bool HasFileBufferType(const FileBufferType &type) const { + return std::find(file_buffer_types.begin(), file_buffer_types.end(), type) != file_buffer_types.end(); + } private: //! Bulk purge dead nodes from the eviction queue. Then, enqueue those that are still alive. @@ -98,11 +105,10 @@ struct EvictionQueue { public: //! The type of the buffers in this queue and helper function (both for verification only) const vector file_buffer_types; - bool HasFileBufferType(const FileBufferType &type) const { - return std::find(file_buffer_types.begin(), file_buffer_types.end(), type) != file_buffer_types.end(); - } //! The concurrent queue eviction_queue_t q; + //! Debug-only: atomic holding the eviction queue sleep setting. + atomic debug_eviction_queue_sleep; private: //! We trigger a purge of the eviction queue every INSERT_INTERVAL insertions @@ -214,9 +220,14 @@ void EvictionQueue::PurgeIteration(const idx_t purge_size) { // retrieve all alive nodes that have been wrongly dequeued idx_t alive_nodes = 0; + auto debug_sleep_micros = debug_eviction_queue_sleep.load(std::memory_order_relaxed); for (idx_t i = 0; i < actually_dequeued; i++) { auto &node = purge_nodes[i]; - auto handle = node.TryGetBlockHandle(); + auto handle = node.TryGetBlockMemory(); + if (debug_sleep_micros > 0) { + // Debug race conditions regarding the ownership of the BlockMemory. + ThreadUtil::SleepMicroSeconds(debug_sleep_micros); + } if (handle) { purge_nodes[alive_nodes++] = std::move(node); } @@ -247,17 +258,17 @@ BufferPool::~BufferPool() { } bool BufferPool::AddToEvictionQueue(shared_ptr &handle) { - auto &queue = GetEvictionQueueForBlockHandle(*handle); + auto &memory = handle->GetMemory(); + auto &queue = GetEvictionQueueForBlockMemory(memory); // The block handle is locked during this operation (Unpin), // or the block handle is still a local variable (ConvertToPersistent) - D_ASSERT(handle->Readers() == 0); - auto ts = handle->NextEvictionSequenceNumber(); + D_ASSERT(memory.GetReaders() == 0); + auto ts = memory.NextEvictionSequenceNumber(); if (track_eviction_timestamps) { - handle->SetLRUTimestamp( - std::chrono::time_point_cast(std::chrono::steady_clock::now()) - .time_since_epoch() - .count()); + memory.SetLRUTimestamp(std::chrono::time_point_cast(std::chrono::steady_clock::now()) + .time_since_epoch() + .count()); } if (ts != 1) { @@ -266,11 +277,12 @@ bool BufferPool::AddToEvictionQueue(shared_ptr &handle) { } // Get the eviction queue for the block and add it - return queue.AddToEvictionQueue(BufferEvictionNode(weak_ptr(handle), ts)); + BufferEvictionNode node(handle->GetMemoryWeak(), ts); + return queue.AddToEvictionQueue(std::move(node)); } -EvictionQueue &BufferPool::GetEvictionQueueForBlockHandle(const BlockHandle &handle) { - const auto &handle_buffer_type = handle.GetBufferType(); +EvictionQueue &BufferPool::GetEvictionQueueForBlockMemory(const BlockMemory &memory) { + const auto &handle_buffer_type = memory.GetBufferType(); // Get offset into eviction queues for this FileBufferType idx_t queue_index = 0; @@ -281,7 +293,7 @@ EvictionQueue &BufferPool::GetEvictionQueueForBlockHandle(const BlockHandle &han const auto &queue_size = eviction_queue_sizes[handle_queue_type_idx]; // Adjust if eviction_queue_idx is set (idx == 0 -> add at back, idx >= queue_size -> add at front) - auto eviction_queue_idx = handle.GetEvictionQueueIndex(); + auto eviction_queue_idx = memory.GetEvictionQueueIndex(); if (eviction_queue_idx < queue_size) { queue_index += queue_size - eviction_queue_idx - 1; } @@ -290,8 +302,8 @@ EvictionQueue &BufferPool::GetEvictionQueueForBlockHandle(const BlockHandle &han return *queues[queue_index]; } -void BufferPool::IncrementDeadNodes(const BlockHandle &handle) { - GetEvictionQueueForBlockHandle(handle).IncrementDeadNodes(); +void BufferPool::IncrementDeadNodes(const BlockMemory &memory) { + GetEvictionQueueForBlockMemory(memory).IncrementDeadNodes(); } void BufferPool::UpdateUsedMemory(MemoryTag tag, int64_t size) { @@ -314,16 +326,50 @@ TemporaryMemoryManager &BufferPool::GetTemporaryMemoryManager() { return *temporary_memory_manager; } +BufferPool::EvictionResult BufferPool::EvictObjectCacheEntries(MemoryTag tag, idx_t extra_memory, idx_t memory_limit) { + TempBufferPoolReservation r(tag, *this, extra_memory); + + if (memory_usage.GetUsedMemory(MemoryUsageCaches::NO_FLUSH) <= memory_limit) { + if (extra_memory > allocator_bulk_deallocation_flush_threshold) { + block_allocator.FlushAll(extra_memory); + } + return {true, std::move(r)}; + } + + bool success = false; + while (!object_cache->IsEmpty()) { + const idx_t freed_mem = object_cache->EvictToReduceMemory(extra_memory); + // Break if all entries cannot be evicted. + if (freed_mem == 0) { + break; + } + + if (memory_usage.GetUsedMemory(MemoryUsageCaches::NO_FLUSH) <= memory_limit) { + success = true; + break; + } + } + if (!success) { + r.Resize(0); + } else if (extra_memory > allocator_bulk_deallocation_flush_threshold) { + block_allocator.FlushAll(extra_memory); + } + + return {success, std::move(r)}; +} + BufferPool::EvictionResult BufferPool::EvictBlocks(MemoryTag tag, idx_t extra_memory, idx_t memory_limit, unique_ptr *buffer) { for (auto &queue : queues) { auto block_result = EvictBlocksInternal(*queue, tag, extra_memory, memory_limit, buffer); - if (block_result.success || RefersToSameObject(*queue, *queues.back())) { - return block_result; // Return upon success or upon last queue + if (block_result.success) { + return block_result; } } - // This can never happen since we always return when i == 1. Exception to silence compiler warning - throw InternalException("Exited BufferPool::EvictBlocksInternal without obtaining BufferPool::EvictionResult"); + + // Evict object cache, which is usually used to cache metadata and configs, when flushing buffer blocks alone is not + // enough to limit overall memory consumption. + return EvictObjectCacheEntries(tag, extra_memory, memory_limit); } BufferPool::EvictionResult BufferPool::EvictBlocksInternal(EvictionQueue &queue, MemoryTag tag, idx_t extra_memory, @@ -338,7 +384,7 @@ BufferPool::EvictionResult BufferPool::EvictBlocksInternal(EvictionQueue &queue, return {true, std::move(r)}; } - queue.IterateUnloadableBlocks([&](BufferEvictionNode &, const shared_ptr &handle, BlockLock &lock) { + queue.IterateUnloadableBlocks([&](BufferEvictionNode &, const shared_ptr &handle, BlockLock &lock) { // hooray, we can unload the block if (buffer && handle->GetBuffer(lock)->AllocSize() == extra_memory) { // we can re-use the memory directly @@ -368,6 +414,8 @@ BufferPool::EvictionResult BufferPool::EvictBlocksInternal(EvictionQueue &queue, return {found, std::move(r)}; } +//! Do not remove this method. +//! There are extensions that rely on time-based purging of blocks, that uses the method. idx_t BufferPool::PurgeAgedBlocks(uint32_t max_age_sec) { int64_t now = std::chrono::time_point_cast(std::chrono::steady_clock::now()) .time_since_epoch() @@ -383,7 +431,7 @@ idx_t BufferPool::PurgeAgedBlocks(uint32_t max_age_sec) { idx_t BufferPool::PurgeAgedBlocksInternal(EvictionQueue &queue, uint32_t max_age_sec, int64_t now, int64_t limit) { idx_t purged_bytes = 0; queue.IterateUnloadableBlocks( - [&](BufferEvictionNode &node, const shared_ptr &handle, BlockLock &lock) { + [&](BufferEvictionNode &node, const shared_ptr &handle, BlockLock &lock) { // We will unload this block regardless. But stop the iteration immediately afterward if this // block is younger than the age threshold. auto lru_timestamp_msec = handle->GetLRUTimestamp(); @@ -398,6 +446,7 @@ idx_t BufferPool::PurgeAgedBlocksInternal(EvictionQueue &queue, uint32_t max_age template void EvictionQueue::IterateUnloadableBlocks(FN fn) { + auto debug_sleep_micros = debug_eviction_queue_sleep.load(std::memory_order_relaxed); for (;;) { // get a block to unpin from the queue BufferEvictionNode node; @@ -410,7 +459,12 @@ void EvictionQueue::IterateUnloadableBlocks(FN fn) { } // get a reference to the underlying block pointer - auto handle = node.TryGetBlockHandle(); + auto handle = node.TryGetBlockMemory(); + if (debug_sleep_micros > 0) { + // Debug race conditions regarding the ownership of the BlockMemory. + // Note that for this to trigger we need at least one purge iteration with the setting active. + ThreadUtil::SleepMicroSeconds(debug_sleep_micros); + } if (!handle) { DecrementDeadNodes(); continue; @@ -431,7 +485,13 @@ void EvictionQueue::IterateUnloadableBlocks(FN fn) { } void BufferPool::PurgeQueue(const BlockHandle &block) { - GetEvictionQueueForBlockHandle(block).Purge(); + const auto &memory = block.GetMemory(); + const auto &buffer_manager = memory.GetBufferManager(); + auto &eviction_queue = GetEvictionQueueForBlockMemory(memory); + const auto queue_sleep_micros = + Settings::Get(buffer_manager.GetDatabase()); + eviction_queue.debug_eviction_queue_sleep = queue_sleep_micros; + eviction_queue.Purge(); } void BufferPool::SetLimit(idx_t limit, const char *exception_postscript) { diff --git a/src/duckdb/src/storage/buffer/buffer_pool_reservation.cpp b/src/duckdb/src/storage/buffer/buffer_pool_reservation.cpp index 783a98079..f9fbe209a 100644 --- a/src/duckdb/src/storage/buffer/buffer_pool_reservation.cpp +++ b/src/duckdb/src/storage/buffer/buffer_pool_reservation.cpp @@ -1,4 +1,5 @@ -#include "duckdb/storage/buffer/block_handle.hpp" +#include "duckdb/storage/buffer/buffer_pool_reservation.hpp" + #include "duckdb/storage/buffer/buffer_pool.hpp" namespace duckdb { diff --git a/src/duckdb/src/storage/buffer_manager.cpp b/src/duckdb/src/storage/buffer_manager.cpp index cbafc4e4a..a99b7a165 100644 --- a/src/duckdb/src/storage/buffer_manager.cpp +++ b/src/duckdb/src/storage/buffer_manager.cpp @@ -119,7 +119,7 @@ unique_ptr BufferManager::ReadTemporaryBuffer(QueryContext context, throw NotImplementedException("This type of BufferManager does not support 'ReadTemporaryBuffer"); } -void BufferManager::DeleteTemporaryFile(BlockHandle &block) { +void BufferManager::DeleteTemporaryFile(BlockMemory &memory) { throw NotImplementedException("This type of BufferManager does not support 'DeleteTemporaryFile"); } diff --git a/src/duckdb/src/storage/caching_file_system.cpp b/src/duckdb/src/storage/caching_file_system.cpp index 1d979377e..2d7a0aa90 100644 --- a/src/duckdb/src/storage/caching_file_system.cpp +++ b/src/duckdb/src/storage/caching_file_system.cpp @@ -49,7 +49,7 @@ bool ShouldExpandToFillGap(const idx_t current_length, const idx_t added_length) } // namespace CachingFileSystem::CachingFileSystem(FileSystem &file_system_p, DatabaseInstance &db_p) - : file_system(file_system_p), external_file_cache(ExternalFileCache::Get(db_p)), db(db_p) { + : file_system(file_system_p), db(db_p), external_file_cache(ExternalFileCache::Get(db)) { } CachingFileSystem::~CachingFileSystem() { diff --git a/src/duckdb/src/storage/caching_file_system_wrapper.cpp b/src/duckdb/src/storage/caching_file_system_wrapper.cpp index a6c8278b4..9b4db4146 100644 --- a/src/duckdb/src/storage/caching_file_system_wrapper.cpp +++ b/src/duckdb/src/storage/caching_file_system_wrapper.cpp @@ -169,7 +169,9 @@ void CachingFileSystemWrapper::Read(FileHandle &handle, void *buffer, int64_t nr } int64_t CachingFileSystemWrapper::Read(FileHandle &handle, void *buffer, int64_t nr_bytes) { - idx_t current_position = SeekPosition(handle); + const idx_t current_position = SeekPosition(handle); + const idx_t max_read = GetFileSize(handle) - current_position; + nr_bytes = MinValue(NumericCast(max_read), nr_bytes); Read(handle, buffer, nr_bytes, current_position); Seek(handle, current_position + NumericCast(nr_bytes)); return nr_bytes; diff --git a/src/duckdb/src/storage/checkpoint/table_data_writer.cpp b/src/duckdb/src/storage/checkpoint/table_data_writer.cpp index b6b18ead7..30c604e68 100644 --- a/src/duckdb/src/storage/checkpoint/table_data_writer.cpp +++ b/src/duckdb/src/storage/checkpoint/table_data_writer.cpp @@ -78,7 +78,7 @@ void SingleFileTableDataWriter::FinalizeTable(const TableStatistics &global_stat RowGroupCollection &collection, Serializer &serializer) { MetaBlockPointer pointer; idx_t total_rows; - auto debug_verify_blocks = DBConfig::GetSetting(GetDatabase()); + auto debug_verify_blocks = Settings::Get(GetDatabase()); if (!existing_pointer.IsValid()) { // write the metadata // store the current position in the metadata writer @@ -172,8 +172,8 @@ void SingleFileTableDataWriter::FinalizeTable(const TableStatistics &global_stat auto index_storage_infos = info.GetIndexes().SerializeToDisk(context, serialization_info); if (debug_verify_blocks) { - for (auto &entry : index_storage_infos) { - for (auto &allocator : entry.allocator_infos) { + for (auto &entry : index_storage_infos.ordered_infos) { + for (auto &allocator : entry.get().allocator_infos) { for (auto &block : allocator.block_pointers) { checkpoint_manager.verify_block_usage_count[block.block_id]++; } @@ -184,7 +184,9 @@ void SingleFileTableDataWriter::FinalizeTable(const TableStatistics &global_stat // write empty block pointers for forwards compatibility vector compat_block_pointers; serializer.WriteProperty(103, "index_pointers", compat_block_pointers); - serializer.WritePropertyWithDefault(104, "index_storage_infos", index_storage_infos); + serializer.WriteList( + 104, "index_storage_infos", index_storage_infos.ordered_infos.size(), + [&](Serializer::List &list, idx_t i) { list.WriteElement(index_storage_infos.ordered_infos[i].get()); }); } } // namespace duckdb diff --git a/src/duckdb/src/storage/checkpoint/write_overflow_strings_to_disk.cpp b/src/duckdb/src/storage/checkpoint/write_overflow_strings_to_disk.cpp index 48ffb70bc..6e7134ed6 100644 --- a/src/duckdb/src/storage/checkpoint/write_overflow_strings_to_disk.cpp +++ b/src/duckdb/src/storage/checkpoint/write_overflow_strings_to_disk.cpp @@ -48,6 +48,18 @@ string UncompressedStringSegmentState::GetSegmentInfo() const { return "Overflow String Block Ids: " + result; } +void UncompressedStringSegmentState::InsertOverflowBlock(block_id_t block_id, reference block) { + auto write_lock = overflow_blocks_lock.GetExclusiveLock(); + overflow_blocks.insert(make_pair(block_id, block)); +} + +reference UncompressedStringSegmentState::FindOverflowBlock(block_id_t block_id) { + auto read_lock = overflow_blocks_lock.GetSharedLock(); + auto entry = overflow_blocks.find(block_id); + D_ASSERT(entry != overflow_blocks.end()); + return entry->second; +} + void WriteOverflowStringsToDisk::WriteString(UncompressedStringSegmentState &state, string_t string, block_id_t &result_block, int32_t &result_offset) { auto &block_manager = partial_block_manager.GetBlockManager(); diff --git a/src/duckdb/src/storage/checkpoint_manager.cpp b/src/duckdb/src/storage/checkpoint_manager.cpp index c1d7a721e..afe7964f5 100644 --- a/src/duckdb/src/storage/checkpoint_manager.cpp +++ b/src/duckdb/src/storage/checkpoint_manager.cpp @@ -9,13 +9,13 @@ #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" #include "duckdb/catalog/duck_catalog.hpp" +#include "duckdb/common/enums/checkpoint_abort.hpp" #include "duckdb/common/serializer/binary_deserializer.hpp" #include "duckdb/common/serializer/binary_serializer.hpp" #include "duckdb/execution/index/art/art.hpp" #include "duckdb/execution/index/unbound_index.hpp" #include "duckdb/main/attached_database.hpp" #include "duckdb/main/client_context.hpp" -#include "duckdb/main/config.hpp" #include "duckdb/main/connection.hpp" #include "duckdb/transaction/duck_transaction_manager.hpp" #include "duckdb/parser/parsed_data/create_schema_info.hpp" @@ -132,6 +132,10 @@ void SingleFileCheckpointWriter::CreateCheckpoint() { if (storage_manager.InMemory()) { return; } + if (ValidChecker::IsInvalidated(db.GetDatabase())) { + // don't checkpoint invalidated databases + return; + } // assert that the checkpoint manager hasn't been used before D_ASSERT(!metadata_writer); @@ -158,121 +162,133 @@ void SingleFileCheckpointWriter::CreateCheckpoint() { ActiveCheckpointWrapper active_checkpoint(transaction_manager); auto has_wal = storage_manager.WALStartCheckpoint(meta_block, options); - auto checkpoint_sleep_ms = DBConfig::GetSetting(db.GetDatabase()); - if (checkpoint_sleep_ms > 0) { - ThreadUtil::SleepMs(checkpoint_sleep_ms); - } - - vector> schemas; - // we scan the set of committed schemas - auto &catalog = Catalog::GetCatalog(db).Cast(); - catalog.ScanSchemas([&](SchemaCatalogEntry &entry) { schemas.push_back(entry); }); - catalog_entry_vector_t catalog_entries; - D_ASSERT(catalog.IsDuckCatalog()); - - auto &dependency_manager = *catalog.GetDependencyManager(); - catalog_entries = GetCatalogEntries(schemas); - dependency_manager.ReorderEntries(catalog_entries); - - // write the actual data into the database - - // Create a serializer to write the checkpoint data - // The serialized format is roughly: - /* - { - schemas: [ - { - schema: , - custom_types: [ { type: }, ... ], - sequences: [ { sequence: }, ... ], - tables: [ { table: }, ... ], - views: [ { view: }, ... ], - macros: [ { macro: }, ... ], - table_macros: [ { table_macro: }, ... ], - indexes: [ { index: , root_offset }, ... ] - } - ] - } - */ - BinarySerializer serializer(*metadata_writer, SerializationOptions(db)); - serializer.Begin(); - serializer.WriteList(100, "catalog_entries", catalog_entries.size(), [&](Serializer::List &list, idx_t i) { - auto &entry = catalog_entries[i]; - list.WriteObject([&](Serializer &obj) { WriteEntry(entry.get(), obj); }); - }); - serializer.End(); - - metadata_writer->Flush(); - table_metadata_writer->Flush(); + try { + auto checkpoint_sleep_ms = Settings::Get(db.GetDatabase()); + if (checkpoint_sleep_ms > 0) { + ThreadUtil::SleepMs(checkpoint_sleep_ms); + } - auto debug_checkpoint_abort = DBConfig::GetSetting(db.GetDatabase()); - if (debug_checkpoint_abort == CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER) { - throw FatalException("Checkpoint aborted before header write because of PRAGMA checkpoint_abort flag"); - } + vector> schemas; + // we scan the set of committed schemas + auto &catalog = Catalog::GetCatalog(db).Cast(); + catalog.ScanSchemas([&](SchemaCatalogEntry &entry) { schemas.push_back(entry); }); + + D_ASSERT(catalog.IsDuckCatalog()); + + auto &dependency_manager = *catalog.GetDependencyManager(); + catalog_entries = GetCatalogEntries(schemas); + dependency_manager.ReorderEntries(catalog_entries); + + // write the actual data into the database + + // Create a serializer to write the checkpoint data + // The serialized format is roughly: + /* + { + schemas: [ + { + schema: , + custom_types: [ { type: }, ... ], + sequences: [ { sequence: }, ... ], + tables: [ { table: }, ... ], + views: [ { view: }, ... ], + macros: [ { macro: }, ... ], + table_macros: [ { table_macro: }, ... ], + indexes: [ { index: , root_offset }, ... ] + } + ] + } + */ + BinarySerializer serializer(*metadata_writer, SerializationOptions(db)); + serializer.Begin(); + serializer.WriteList(100, "catalog_entries", catalog_entries.size(), [&](Serializer::List &list, idx_t i) { + auto &entry = catalog_entries[i]; + list.WriteObject([&](Serializer &obj) { WriteEntry(entry.get(), obj); }); + }); + serializer.End(); - // finally write the updated header - DatabaseHeader header; - header.meta_block = meta_block.block_pointer; - header.block_alloc_size = block_manager.GetBlockAllocSize(); - header.vector_size = STANDARD_VECTOR_SIZE; - block_manager.WriteHeader(context, header); + metadata_writer->Flush(); + table_metadata_writer->Flush(); - auto debug_verify_blocks = DBConfig::GetSetting(db.GetDatabase()); - if (debug_verify_blocks) { - // extend verify_block_usage_count - auto metadata_info = storage_manager.GetMetadataInfo(); - for (auto &info : metadata_info) { - verify_block_usage_count[info.block_id]++; + auto debug_checkpoint_abort = Settings::Get(db.GetDatabase()); + if (debug_checkpoint_abort == CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER) { + throw FatalException("Checkpoint aborted before header write because of PRAGMA checkpoint_abort flag"); } - for (auto &entry_ref : catalog_entries) { - auto &entry = entry_ref.get(); - if (entry.type != CatalogType::TABLE_ENTRY) { - continue; + + // finally write the updated header + DatabaseHeader header; + header.meta_block = meta_block.block_pointer; + header.block_alloc_size = block_manager.GetBlockAllocSize(); + header.vector_size = STANDARD_VECTOR_SIZE; + block_manager.WriteHeader(context, header); + + auto debug_verify_blocks = Settings::Get(db.GetDatabase()); + if (debug_verify_blocks) { + // extend verify_block_usage_count + auto metadata_info = storage_manager.GetMetadataInfo(); + for (auto &info : metadata_info) { + verify_block_usage_count[info.block_id]++; } - auto &table = entry.Cast(); - auto &storage = table.GetStorage(); - auto segment_info = storage.GetColumnSegmentInfo(context); - for (auto &segment : segment_info) { - verify_block_usage_count[segment.block_id]++; - if (StringUtil::Contains(segment.segment_info, "Overflow String Block Ids: ")) { - auto overflow_blocks = StringUtil::Replace(segment.segment_info, "Overflow String Block Ids: ", ""); - auto splits = StringUtil::Split(overflow_blocks, ", "); - for (auto &split : splits) { - auto overflow_block_id = std::stoll(split); - verify_block_usage_count[overflow_block_id]++; + for (auto &entry_ref : catalog_entries) { + auto &entry = entry_ref.get(); + if (entry.type != CatalogType::TABLE_ENTRY) { + continue; + } + auto &table = entry.Cast(); + auto &storage = table.GetStorage(); + auto segment_info = storage.GetColumnSegmentInfo(context); + for (auto &segment : segment_info) { + verify_block_usage_count[segment.block_id]++; + if (StringUtil::Contains(segment.segment_info, "Overflow String Block Ids: ")) { + auto overflow_blocks = + StringUtil::Replace(segment.segment_info, "Overflow String Block Ids: ", ""); + auto splits = StringUtil::Split(overflow_blocks, ", "); + for (auto &split : splits) { + auto overflow_block_id = std::stoll(split); + verify_block_usage_count[overflow_block_id]++; + } } } } + block_manager.VerifyBlocks(verify_block_usage_count); } - block_manager.VerifyBlocks(verify_block_usage_count); - } - if (debug_checkpoint_abort == CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE) { - throw FatalException("Checkpoint aborted before truncate because of PRAGMA checkpoint_abort flag"); - } + if (debug_checkpoint_abort == CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE) { + throw FatalException("Checkpoint aborted before truncate because of PRAGMA checkpoint_abort flag"); + } - // truncate the file - block_manager.Truncate(); + // truncate the file + block_manager.Truncate(); - if (debug_checkpoint_abort == CheckpointAbort::DEBUG_ABORT_BEFORE_WAL_FINISH) { - throw FatalException("Checkpoint aborted before truncate because of PRAGMA checkpoint_abort flag"); - } + if (debug_checkpoint_abort == CheckpointAbort::DEBUG_ABORT_BEFORE_WAL_FINISH) { + throw FatalException("Checkpoint aborted before truncate because of PRAGMA checkpoint_abort flag"); + } - // truncate the WAL - unique_ptr> wal_lock; - if (has_wal) { - wal_lock = storage_manager.GetWALLock(); - storage_manager.WALFinishCheckpoint(*wal_lock); + // truncate the WAL + if (has_wal) { + unique_ptr> owned_wal_lock; + optional_ptr> wal_lock; + if (!options.wal_lock) { + // not holding the WAL lock yet - grab it + owned_wal_lock = storage_manager.GetWALLock(); + wal_lock = *owned_wal_lock; + } else { + // we already have the WAL lock - just refer to it + wal_lock = options.wal_lock; + } + storage_manager.WALFinishCheckpoint(*wal_lock); + } + } catch (std::exception &ex) { + // any exceptions thrown here are fatal + ErrorData error(ex); + if (error.Type() == ExceptionType::FATAL) { + ValidChecker::Invalidate(db.GetDatabase(), error.Message()); + throw; + } + throw FatalException("Failed to create checkpoint: %s", error.Message()); } - // FIXME: hold the WAL lock while we are merging checkpoint deltas - // this prevents any commits from happening while this is going on - // this is currently required because of the way that "deletes + inserts" of the same row are processed - // currently we FIRST append the new (duplicate) insert, THEN delete the old value - // if we append the duplicate value, then call MergeCheckpointDeltas, that will fail with a duplicate entry error - // we can fix this and stop holding the WAL lock once we fix / remove that order of operations in the commit - // for any indexes that were appended to while checkpointing, merge the delta back into the main index // FIXME: we only clean up appends made to tables that are part of this checkpoint // Currently, that is correct, since we don't allow creating tables DURING a checkpoint @@ -289,8 +305,9 @@ void SingleFileCheckpointWriter::CreateCheckpoint() { auto &storage = table.GetStorage(); auto &table_info = storage.GetDataTableInfo(); auto &index_list = table_info->GetIndexes(); - index_list.MergeCheckpointDeltas(storage, options.transaction_id); + index_list.MergeCheckpointDeltas(options.transaction_id); } + active_checkpoint.Clear(); } void CheckpointReader::LoadCheckpoint(CatalogTransaction transaction, MetadataReader &reader) { @@ -512,22 +529,16 @@ void CheckpointReader::ReadIndex(CatalogTransaction transaction, Deserializer &d // Read older duckdb files. index_storage_info.name = index.name; index_storage_info.root_block_ptr = root_block_pointer; - } else { - // Read the matching index storage info. - for (auto const &elem : table_info->GetIndexStorageInfo()) { - if (elem.name == index.name) { - index_storage_info = elem; - break; - } - } + // Extract the matching index storage info (moves it out of the stored collection). + index_storage_info = table_info->ExtractIndexStorageInfo(index.name); } D_ASSERT(index_storage_info.IsValid()); D_ASSERT(!index_storage_info.name.empty()); // Create an unbound index and add it to the table. - auto unbound_index = make_uniq(std::move(create_info), index_storage_info, + auto unbound_index = make_uniq(std::move(create_info), std::move(index_storage_info), TableIOManager::Get(data_table), data_table.db); table_info->GetIndexes().AddIndex(std::move(unbound_index)); } @@ -622,7 +633,7 @@ void CheckpointReader::ReadTableData(CatalogTransaction transaction, Deserialize deserializer.ReadPropertyWithExplicitDefault>(104, "index_storage_infos", {}); if (!index_storage_infos.empty()) { - bound_info.indexes = index_storage_infos; + bound_info.indexes = std::move(index_storage_infos); } else { // This is an old duckdb file containing index pointers and deprecated storage. @@ -630,7 +641,7 @@ void CheckpointReader::ReadTableData(CatalogTransaction transaction, Deserialize // Deprecated storage is always true for old duckdb files. IndexStorageInfo index_storage_info; index_storage_info.root_block_ptr = index_pointers[i]; - bound_info.indexes.push_back(index_storage_info); + bound_info.indexes.push_back(std::move(index_storage_info)); } } diff --git a/src/duckdb/src/storage/compression/bitpacking.cpp b/src/duckdb/src/storage/compression/bitpacking.cpp index a5f3ccc35..6c057f6dd 100644 --- a/src/duckdb/src/storage/compression/bitpacking.cpp +++ b/src/duckdb/src/storage/compression/bitpacking.cpp @@ -9,6 +9,7 @@ #include "duckdb/function/compression/compression.hpp" #include "duckdb/function/compression_function.hpp" #include "duckdb/main/config.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/storage/buffer_manager.hpp" #include "duckdb/storage/compression/bitpacking.hpp" #include "duckdb/storage/table/column_data_checkpointer.hpp" @@ -22,40 +23,6 @@ namespace duckdb { constexpr const idx_t BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE; static constexpr const idx_t BITPACKING_METADATA_GROUP_SIZE = STANDARD_VECTOR_SIZE > 512 ? STANDARD_VECTOR_SIZE : 2048; -BitpackingMode BitpackingModeFromString(const string &str) { - auto mode = StringUtil::Lower(str); - if (mode == "auto" || mode == "none") { - return BitpackingMode::AUTO; - } else if (mode == "constant") { - return BitpackingMode::CONSTANT; - } else if (mode == "constant_delta") { - return BitpackingMode::CONSTANT_DELTA; - } else if (mode == "delta_for") { - return BitpackingMode::DELTA_FOR; - } else if (mode == "for") { - return BitpackingMode::FOR; - } else { - return BitpackingMode::INVALID; - } -} - -string BitpackingModeToString(const BitpackingMode &mode) { - switch (mode) { - case BitpackingMode::AUTO: - return "auto"; - case BitpackingMode::CONSTANT: - return "constant"; - case BitpackingMode::CONSTANT_DELTA: - return "constant_delta"; - case BitpackingMode::DELTA_FOR: - return "delta_for"; - case BitpackingMode::FOR: - return "for"; - default: - throw NotImplementedException("Unknown bitpacking mode: " + to_string((uint8_t)mode) + "\n"); - } -} - typedef struct { BitpackingMode mode; uint32_t offset; @@ -338,11 +305,9 @@ struct BitpackingAnalyzeState : public AnalyzeState { template unique_ptr BitpackingInitAnalyze(ColumnData &col_data, PhysicalType type) { - auto &config = DBConfig::GetConfig(col_data.GetDatabase()); - CompressionInfo info(col_data.GetBlockManager()); auto state = make_uniq>(info); - state->state.mode = config.options.force_bitpacking_mode; + state->state.mode = Settings::Get(col_data.GetDatabase()); return std::move(state); } @@ -393,9 +358,7 @@ struct BitpackingCompressionState : public CompressionState { CreateEmptySegment(); state.data_ptr = reinterpret_cast(this); - - auto &config = DBConfig::GetConfig(checkpoint_data.GetDatabase()); - state.mode = config.options.force_bitpacking_mode; + state.mode = Settings::Get(checkpoint_data.GetDatabase()); } ColumnDataCheckpointData &checkpoint_data; @@ -679,7 +642,7 @@ struct BitpackingScanState : public SegmentScanState { //! depending on the bitpacking mode of that group. void LoadNextGroup() { D_ASSERT(bitpacking_metadata_ptr > handle.Ptr() && - (bitpacking_metadata_ptr < handle.Ptr() + current_segment.GetBlockManager().GetBlockSize())); + (bitpacking_metadata_ptr < handle.Ptr() + current_segment.GetBlockSize())); current_group_offset = 0; current_group = DecodeMeta(reinterpret_cast(bitpacking_metadata_ptr)); diff --git a/src/duckdb/src/storage/compression/dict_fsst/decompression.cpp b/src/duckdb/src/storage/compression/dict_fsst/decompression.cpp index f6befffe5..c27efd1e5 100644 --- a/src/duckdb/src/storage/compression/dict_fsst/decompression.cpp +++ b/src/duckdb/src/storage/compression/dict_fsst/decompression.cpp @@ -10,7 +10,7 @@ CompressedStringScanState::~CompressedStringScanState() { } string_t CompressedStringScanState::FetchStringFromDict(Vector &result, uint32_t dict_offset, idx_t dict_idx) { - D_ASSERT(dict_offset <= NumericCast(segment.GetBlockManager().GetBlockSize())); + D_ASSERT(dict_offset <= NumericCast(segment.GetBlockSize())); if (dict_idx == 0) { return string_t(nullptr, 0); @@ -69,7 +69,7 @@ void CompressedStringScanState::Initialize(bool initialize_dictionary) { auto dictionary_indices_dest = AlignValue(string_lengths_dest + string_lengths_space); const auto total_space = segment.GetBlockOffset() + dictionary_indices_dest + dictionary_indices_space; - if (total_space > segment.GetBlockManager().GetBlockSize()) { + if (total_space > segment.GetBlockSize()) { throw IOException( "Failed to scan dictionary string - index was out of range. Database file appears to be corrupted."); } diff --git a/src/duckdb/src/storage/compression/dictionary/decompression.cpp b/src/duckdb/src/storage/compression/dictionary/decompression.cpp index 6e389d026..cf631b6f9 100644 --- a/src/duckdb/src/storage/compression/dictionary/decompression.cpp +++ b/src/duckdb/src/storage/compression/dictionary/decompression.cpp @@ -33,14 +33,14 @@ void CompressedStringScanState::Initialize(ColumnSegment &segment, bool initiali index_buffer_count = Load(data_ptr_cast(&header_ptr->index_buffer_count)); current_width = (bitpacking_width_t)(Load(data_ptr_cast(&header_ptr->bitpacking_width))); if (segment.GetBlockOffset() + index_buffer_offset + sizeof(uint32_t) * index_buffer_count > - segment.GetBlockManager().GetBlockSize()) { + segment.GetBlockSize()) { throw IOException( "Failed to scan dictionary string - index was out of range. Database file appears to be corrupted."); } index_buffer_ptr = reinterpret_cast(baseptr + index_buffer_offset); base_data = data_ptr_cast(baseptr + DictionaryCompression::DICTIONARY_HEADER_SIZE); - block_size = segment.GetBlockManager().GetBlockSize(); + block_size = segment.GetBlockSize(); dict = DictionaryCompression::GetDictionary(segment, *handle); if (!initialize_dictionary) { diff --git a/src/duckdb/src/storage/compression/fsst.cpp b/src/duckdb/src/storage/compression/fsst.cpp index faf9c5f93..4bd713b2e 100644 --- a/src/duckdb/src/storage/compression/fsst.cpp +++ b/src/duckdb/src/storage/compression/fsst.cpp @@ -573,7 +573,7 @@ struct FSSTScanState : public StringScanState { }; unique_ptr FSSTStorage::StringInitScan(const QueryContext &context, ColumnSegment &segment) { - auto block_size = segment.GetBlockManager().GetBlockSize(); + auto block_size = segment.GetBlockSize(); auto string_block_limit = StringUncompressed::GetStringBlockLimit(block_size); auto state = make_uniq(string_block_limit); auto &buffer_manager = BufferManager::GetBufferManager(segment.db); @@ -649,7 +649,7 @@ void FSSTStorage::StringScanPartial(ColumnSegment &segment, ColumnScanState &sta bool enable_fsst_vectors; if (ALLOW_FSST_VECTORS) { - enable_fsst_vectors = DBConfig::GetSetting(segment.db); + enable_fsst_vectors = Settings::Get(segment.db); } else { enable_fsst_vectors = false; } @@ -668,7 +668,7 @@ void FSSTStorage::StringScanPartial(ColumnSegment &segment, ColumnScanState &sta if (scan_state.duckdb_fsst_decoder) { D_ASSERT(result_offset == 0 || result.GetVectorType() == VectorType::FSST_VECTOR); result.SetVectorType(VectorType::FSST_VECTOR); - auto string_block_limit = StringUncompressed::GetStringBlockLimit(segment.GetBlockManager().GetBlockSize()); + auto string_block_limit = StringUncompressed::GetStringBlockLimit(segment.GetBlockSize()); FSSTVector::RegisterDecoder(result, scan_state.duckdb_fsst_decoder, string_block_limit); result_data = FSSTVector::GetCompressedData(result); } else { @@ -745,7 +745,7 @@ void FSSTStorage::StringFetchRow(ColumnSegment &segment, ColumnFetchState &state duckdb_fsst_decoder_t decoder; bitpacking_width_t width; - auto block_size = segment.GetBlockManager().GetBlockSize(); + auto block_size = segment.GetBlockSize(); auto have_symbol_table = ParseFSSTSegmentHeader(base_ptr, &decoder, &width, block_size); auto result_data = FlatVector::GetData(result); diff --git a/src/duckdb/src/storage/compression/rle.cpp b/src/duckdb/src/storage/compression/rle.cpp index 1b4699259..fd31d8f04 100644 --- a/src/duckdb/src/storage/compression/rle.cpp +++ b/src/duckdb/src/storage/compression/rle.cpp @@ -264,7 +264,7 @@ struct RLEScanState : public SegmentScanState { entry_pos = 0; position_in_entry = 0; rle_count_offset = UnsafeNumericCast(Load(handle.Ptr() + segment.GetBlockOffset())); - D_ASSERT(rle_count_offset <= segment.GetBlockManager().GetBlockSize()); + D_ASSERT(rle_count_offset <= segment.GetBlockSize()); } inline void SkipInternal(rle_count_t *index_pointer, idx_t skip_count) { diff --git a/src/duckdb/src/storage/compression/string_uncompressed.cpp b/src/duckdb/src/storage/compression/string_uncompressed.cpp index f2c246cce..4b9dc8519 100644 --- a/src/duckdb/src/storage/compression/string_uncompressed.cpp +++ b/src/duckdb/src/storage/compression/string_uncompressed.cpp @@ -68,7 +68,7 @@ void UncompressedStringInitPrefetch(ColumnSegment &segment, PrefetchState &prefe auto segment_state = segment.GetSegmentState(); if (segment_state) { auto &state = segment_state->Cast(); - auto &block_manager = segment.GetBlockManager(); + auto &block_manager = segment.block->GetBlockManager(); for (auto &block_id : state.on_disk_blocks) { auto block_handle = state.GetHandle(block_manager, block_id); prefetch_state.AddBlock(block_handle); @@ -221,7 +221,7 @@ idx_t UncompressedStringStorage::FinalizeAppend(ColumnSegment &segment, SegmentS auto offset_size = DICTIONARY_HEADER_SIZE + segment.count * sizeof(int32_t); auto total_size = offset_size + dict.size; - CompressionInfo info(segment.GetBlockManager()); + CompressionInfo info(segment.block->GetBlockManager()); if (total_size >= info.GetCompactionFlushLimit()) { // the block is full enough, don't bother moving around the dictionary return segment.SegmentSize(); @@ -337,14 +337,14 @@ void UncompressedStringStorage::WriteStringMemory(ColumnSegment &segment, string if (!state.head || state.head->offset + total_length >= state.head->size) { // string does not fit, allocate space for it // create a new string block - auto alloc_size = MaxValue(total_length, segment.GetBlockManager().GetBlockSize()); + auto alloc_size = MaxValue(total_length, segment.GetBlockSize()); auto new_block = make_uniq(); new_block->offset = 0; new_block->size = alloc_size; // allocate an in-memory buffer for it handle = buffer_manager.Allocate(MemoryTag::OVERFLOW_STRINGS, alloc_size, false); block = handle.GetBlockHandle(); - state.overflow_blocks.insert(make_pair(block->BlockId(), reference(*new_block))); + state.InsertOverflowBlock(block->BlockId(), reference(*new_block)); new_block->block = std::move(block); new_block->next = std::move(state.head); state.head = std::move(new_block); @@ -366,17 +366,16 @@ void UncompressedStringStorage::WriteStringMemory(ColumnSegment &segment, string string_t UncompressedStringStorage::ReadOverflowString(ColumnSegment &segment, Vector &result, block_id_t block, int32_t offset) { - auto &block_manager = segment.GetBlockManager(); - auto &buffer_manager = block_manager.buffer_manager; + auto &buffer_manager = segment.block->GetMemory().GetBufferManager(); auto &state = segment.GetSegmentState()->Cast(); D_ASSERT(block != INVALID_BLOCK); - D_ASSERT(offset < NumericCast(block_manager.GetBlockSize())); + D_ASSERT(offset < NumericCast(segment.GetBlockSize())); if (block < MAXIMUM_BLOCK) { // read the overflow string from disk // pin the initial handle and read the length - auto block_handle = state.GetHandle(block_manager, block); + auto block_handle = state.GetHandle(segment.block->GetBlockManager(), block); auto handle = buffer_manager.Pin(block_handle); // read header @@ -387,7 +386,7 @@ string_t UncompressedStringStorage::ReadOverflowString(ColumnSegment &segment, V BufferHandle target_handle; string_t overflow_string; data_ptr_t target_ptr; - bool allocate_block = length >= block_manager.GetBlockSize(); + bool allocate_block = length >= segment.GetBlockSize(); if (allocate_block) { // overflow string is bigger than a block - allocate a temporary buffer for it target_handle = buffer_manager.Allocate(MemoryTag::OVERFLOW_STRINGS, length); @@ -400,7 +399,7 @@ string_t UncompressedStringStorage::ReadOverflowString(ColumnSegment &segment, V // now append the string to the single buffer while (remaining > 0) { - idx_t to_write = MinValue(remaining, block_manager.GetBlockSize() - sizeof(block_id_t) - + idx_t to_write = MinValue(remaining, segment.GetBlockSize() - sizeof(block_id_t) - UnsafeNumericCast(offset)); memcpy(target_ptr, handle.Ptr() + offset, to_write); remaining -= to_write; @@ -409,7 +408,7 @@ string_t UncompressedStringStorage::ReadOverflowString(ColumnSegment &segment, V if (remaining > 0) { // read the next block block_id_t next_block = Load(handle.Ptr() + offset); - block_handle = state.GetHandle(block_manager, next_block); + block_handle = state.GetHandle(segment.block->GetBlockManager(), next_block); handle = buffer_manager.Pin(block_handle); offset = 0; } @@ -426,9 +425,8 @@ string_t UncompressedStringStorage::ReadOverflowString(ColumnSegment &segment, V // read the overflow string from memory // first pin the handle, if it is not pinned yet - auto entry = state.overflow_blocks.find(block); - D_ASSERT(entry != state.overflow_blocks.end()); - auto handle = buffer_manager.Pin(entry->second.get().block); + auto string_block = state.FindOverflowBlock(block); + auto handle = buffer_manager.Pin(string_block.get().block); auto final_buffer = handle.Ptr(); StringVector::AddHandle(result, std::move(handle)); return ReadStringWithLength(final_buffer, offset); diff --git a/src/duckdb/src/storage/compression/validity_uncompressed.cpp b/src/duckdb/src/storage/compression/validity_uncompressed.cpp index 49e3c2dc8..fd0fd193f 100644 --- a/src/duckdb/src/storage/compression/validity_uncompressed.cpp +++ b/src/duckdb/src/storage/compression/validity_uncompressed.cpp @@ -223,12 +223,35 @@ void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx auto &result_mask = FlatVector::Validity(result); auto input_data = reinterpret_cast(input); +#ifdef DEBUG + // save boundary entries to verify we don't corrupt surrounding bits later. + idx_t debug_first_entry = result_offset / ValidityMask::BITS_PER_VALUE; + idx_t debug_last_entry = (result_offset + scan_count - 1) / ValidityMask::BITS_PER_VALUE; + auto debug_result_data = (validity_t *)result_mask.GetData(); + validity_t debug_original_first_entry = + debug_result_data ? debug_result_data[debug_first_entry] : ValidityMask::ValidityBuffer::MAX_ENTRY; + validity_t debug_original_last_entry = + debug_result_data ? debug_result_data[debug_last_entry] : ValidityMask::ValidityBuffer::MAX_ENTRY; + + // save original result validity for in-range verification (usually this function is meant to be called + // with all result bits set to valid, but in some instances, the result bits may be invalid, in which case, + // the result bits should remain invalid, i.e. we do not copy over the input bit. + ValidityMask debug_original_result(scan_count); + if (debug_result_data) { + for (idx_t i = 0; i < scan_count; i++) { + if (!result_mask.RowIsValid(result_offset + i)) { + debug_original_result.SetInvalid(i); + } + } + } +#endif + #if STANDARD_VECTOR_SIZE < 128 // fallback for tiny vector sizes // the bitwise ops we use below don't work if the vector size is too small - ValidityMask source_mask(input_data, input_size); + ValidityMask source_mask128(input_data, input_size); for (idx_t i = 0; i < scan_count; i++) { - if (!source_mask.RowIsValid(input_start + i)) { + if (!source_mask128.RowIsValid(input_start + i)) { if (result_mask.AllValid()) { result_mask.Initialize(); } @@ -248,118 +271,163 @@ void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx idx_t input_entry = input_start / ValidityMask::BITS_PER_VALUE; idx_t input_idx = input_start - input_entry * ValidityMask::BITS_PER_VALUE; + // Window scanning algorithm -- the goal is to copy a contiguous sequence of bits from input into result, + // and to do this using bit operations on 64 bit fields. + // + // The algorithm is simply explained with the diagram below: each loop iteration is numbered, and within each + // iteration we are copying the numbered window from the input to the corresponding window in the result. + // + // input_entry and result_entry are the 64 bit entries, i.e. on any given loop iteration we only want to be + // performing bit operations on 64 bit entries. + // + // input_index and result_index are the current offset within each entry. We can calculate the current window size + // as the minimum between the remaining bits to process in each entry. + // + // INPUT: + // 0 63| 127| 191 + // +-------------------------------+--------------------------------+--------------------------------+ + // | [ 1 ]|[ 2 ][ 3 ]|[ 4 ][ 5 ]| + // +-------------------------------+--------------------------------+--------------------------------+ + // + // RESULT: + // 0 63| 127| 191 + // +-------------------------------+--------------------------------+--------------------------------+ + // [ 1 ][ 2 ]|[ 3 ][ 4 ]|[ 5 ] | + // +-------------------------------+--------------------------------+--------------------------------+ + // + // Note: in case this ever becomes a bottleneck, it should be possible to make each loop iteration branchless. + // The idea would be to do an odd iteration before the loop, then have two loops depending on the layout of the + // windows that will either shift left then right on each iteration, or the other loop will always shift right + // then left. For example, in the diagram above, we would first apply the first window outside of the loop + // beforehand, then we can see that each loop iteration requires us to shift right, fetch a new result entry, + // shift left, fetch a new input entry. This would have to be generalized to two possible branchless loops, + // depending on the input. + // now start the bit games idx_t pos = 0; while (pos < scan_count) { - // these are the current validity entries we are dealing with - idx_t current_result_idx = result_entry; - idx_t offset; validity_t input_mask = input_data[input_entry]; + idx_t bits_left = scan_count - pos; - // construct the mask to AND together with the result - if (result_idx < input_idx) { - // +======================================+ - // input: |xxxxxxxxx| | - // +======================================+ - // - // +======================================+ - // result: | xxxxxxxxx| | - // +======================================+ - // 1. We shift (>>) 'input' to line up with 'result' - // 2. We set the bits we shifted to 1 + // these are bits left within the current entries (possibly extra than what we need). + idx_t input_bits_left = ValidityMask::BITS_PER_VALUE - input_idx; + idx_t result_bits_left = ValidityMask::BITS_PER_VALUE - result_idx; - // we have to shift the input RIGHT if the result_idx is smaller than the input_idx - auto shift_amount = input_idx - result_idx; - D_ASSERT(shift_amount > 0 && shift_amount <= ValidityMask::BITS_PER_VALUE); + // these are the bits left within the current entries that need to be processed. + idx_t input_window_size = MinValue(bits_left, input_bits_left); + idx_t result_window_size = MinValue(bits_left, result_bits_left); - input_mask = input_mask >> shift_amount; - - // now the upper "shift_amount" bits are set to 0 - // we need them to be set to 1 - // otherwise the subsequent bitwise & will modify values outside of the range of values we want to alter - input_mask |= ValidityUncompressed::UPPER_MASKS[shift_amount]; + // the smaller of the two is our next window to copy from input to result. + idx_t window_size = MinValue(input_window_size, result_window_size); - if (pos == 0) { - // We also need to set the lower bits, which are to the left of the relevant bits (x), to 1 - // These are the bits that are "behind" this scan window, and should not affect this scan - auto non_relevant_mask = ValidityUncompressed::LOWER_MASKS[result_idx]; - input_mask |= non_relevant_mask; - } + // Within each loop iteration, copy the window from the starting index in input over to the starting index + // of result, without corrupting surrounding bits in the result entry. - // after this, we move to the next input_entry - offset = ValidityMask::BITS_PER_VALUE - input_idx; - input_entry++; - input_idx = 0; - result_idx += offset; - } else if (result_idx > input_idx) { - // +======================================+ - // input: | xxxxxxxxx| | - // +======================================+ + // First, line up the windows: + if (result_idx < input_idx) { + // X is arbitrary bits, P is arbitrary protected bits. + // INPUT ENTRY: + // 63 0 + // +--------------------------------------------------------------------------------------------------+ + // |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX[=============WINDOW=============]XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| + // +--------------------------------------------------------------------------------------------------+ + // ^ + // input_idx // - // +======================================+ - // result: |xxxxxxxxx| | - // +======================================+ - // 1. We set the bits to the left of the relevant bits (x) to 0 - // 1. We shift (<<) 'input' to line up with 'result' - // 2. We set the bits that we zeroed to the right of the relevant bits (x) to 1 - - // we have to shift the input LEFT if the result_idx is bigger than the input_idx - auto shift_amount = result_idx - input_idx; - D_ASSERT(shift_amount > 0 && shift_amount <= ValidityMask::BITS_PER_VALUE); - - // to avoid overflows, we set the upper "shift_amount" values to 0 first - input_mask = (input_mask & ~ValidityUncompressed::UPPER_MASKS[shift_amount]) << shift_amount; - - // now the lower "shift_amount" bits are set to 0 - // we need them to be set to 1 - // otherwise the subsequent bitwise & will modify values outside of the range of values we want to alter - input_mask |= ValidityUncompressed::LOWER_MASKS[shift_amount]; - - // after this, we move to the next result_entry - offset = ValidityMask::BITS_PER_VALUE - result_idx; - result_entry++; - result_idx = 0; - input_idx += offset; - } else { - // if the input_idx is equal to result_idx they are already aligned - // we just move to the next entry for both after this - offset = ValidityMask::BITS_PER_VALUE - result_idx; - input_entry++; - result_entry++; - result_idx = input_idx = 0; - } - // now we need to check if we should include the ENTIRE mask - // OR if we need to mask from the right side - pos += offset; - if (pos > scan_count) { - // +======================================+ - // mask: | |xxxxxxxxxxxxxxxxxxxxxxxxx| - // +======================================+ + // RESULT ENTRY: + // 63 0 + // +--------------------------------------------------------------------------------------------------+ + // |PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP[=============WINDOW=============]PPPPPPPPPPPPPPPPPPPPPP| + // +--------------------------------------------------------------------------------------------------+ + // ^ + // result_idx // - // The bits on the right side of the relevant bits (x) need to stay 1, to be adjusted by later scans - // so we adjust the mask to clear out any 0s that might be present on the right side. + idx_t shift_amount = input_idx - result_idx; + input_mask = input_mask >> shift_amount; + } else { + // current_result_idx >= current_input_idx + idx_t shift_amount = result_idx - input_idx; + input_mask = (input_mask & ~UPPER_MASKS[shift_amount]); - // we need to set any bits that are past the scan_count on the right-side to 1 - // this is required so we don't influence any bits that are not part of the scan - input_mask |= ValidityUncompressed::UPPER_MASKS[pos - scan_count]; + // X is arbitrary bits, P is arbitrary protected bits. + // Note the zeroed out bits in INPUT_ENTRY - these have to be zeroed before shifting left to align with + // result window, to prevent overflow. + // + // INPUT ENTRY: + // 63 0 + // +--------------------------------------------------------------------------------------------------+ + // |000000000000XXXXXXXXXXXXXXXXXXXX[=============WINDOW=============]XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| + // +--------------------------------------------------------------------------------------------------+ + // ^ + // input_idx + // + // RESULT ENTRY: + // 63 0 + // +--------------------------------------------------------------------------------------------------+ + // |PPPPPPPPPPPPPPPPPPPP[=============WINDOW=============]PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP| + // +--------------------------------------------------------------------------------------------------+ + // ^ + // result_idx + input_mask = input_mask << shift_amount; } - // now finally we can merge the input mask with the result mask + + // Once the windows are aligned, mask the input to prevent overwriting protected bits in the result_mask. + auto protected_upper_bits = UPPER_MASKS[ValidityMask::BITS_PER_VALUE - result_idx - window_size]; + auto protected_lower_bits = LOWER_MASKS[result_idx]; + input_mask |= protected_upper_bits; + input_mask |= protected_lower_bits; + if (input_mask != ValidityMask::ValidityBuffer::MAX_ENTRY) { if (!result_data) { result_mask.Initialize(); result_data = (validity_t *)result_mask.GetData(); } - result_data[current_result_idx] &= input_mask; + result_data[result_entry] &= input_mask; + } + // Now update pos, entries, and indexes for the next iteration. + pos += window_size; + + // Windows can only go until the end of the current entry, so the mod can only wrap to 0 here. + input_idx = (input_idx + window_size) % ValidityMask::BITS_PER_VALUE; + result_idx = (result_idx + window_size) % ValidityMask::BITS_PER_VALUE; + + // Advance entries if the mod was 0. + if (input_idx == 0) { + input_entry++; + } + if (result_idx == 0) { + result_entry++; } } #endif #ifdef DEBUG - // verify that we actually accomplished the bitwise ops equivalent that we wanted to do - ValidityMask input_mask(input_data, input_size); + // verify in-range bits. + ValidityMask source_mask(input_data, input_size); for (idx_t i = 0; i < scan_count; i++) { - D_ASSERT(result_mask.RowIsValid(result_offset + i) == input_mask.RowIsValid(input_start + i)); + bool original_valid = debug_original_result.RowIsValid(i); + bool input_valid = source_mask.RowIsValid(input_start + i); + bool result_valid = result_mask.RowIsValid(result_offset + i); + D_ASSERT(result_valid == (original_valid && input_valid)); } + + // verify surrounding bits weren't modified + auto debug_final_result_data = (validity_t *)result_mask.GetData(); + validity_t debug_final_first_entry = + debug_final_result_data ? debug_final_result_data[debug_first_entry] : ValidityMask::ValidityBuffer::MAX_ENTRY; + validity_t debug_final_last_entry = + debug_final_result_data ? debug_final_result_data[debug_last_entry] : ValidityMask::ValidityBuffer::MAX_ENTRY; + + idx_t first_bit_in_first_entry = result_offset % ValidityMask::BITS_PER_VALUE; + idx_t last_bit_in_last_entry = (result_offset + scan_count - 1) % ValidityMask::BITS_PER_VALUE; + + // lower bits of first entry should be unchanged + validity_t lower_mask = LOWER_MASKS[first_bit_in_first_entry]; + D_ASSERT((debug_original_first_entry & lower_mask) == (debug_final_first_entry & lower_mask)); + + // upper bits of last entry should be unchanged + validity_t upper_mask = UPPER_MASKS[ValidityMask::BITS_PER_VALUE - last_bit_in_last_entry - 1]; + D_ASSERT((debug_original_last_entry & upper_mask) == (debug_final_last_entry & upper_mask)); #endif } diff --git a/src/duckdb/src/storage/compression/zstd.cpp b/src/duckdb/src/storage/compression/zstd.cpp index d727cf1ea..632e5f5a7 100644 --- a/src/duckdb/src/storage/compression/zstd.cpp +++ b/src/duckdb/src/storage/compression/zstd.cpp @@ -3,11 +3,13 @@ #include "duckdb/storage/table/column_data_checkpointer.hpp" #include "duckdb/storage/block_manager.hpp" #include "duckdb/main/config.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/common/constants.hpp" #include "duckdb/common/allocator.hpp" #include "duckdb/common/serializer/deserializer.hpp" #include "duckdb/storage/checkpoint/string_checkpoint_state.hpp" +#include "duckdb/storage/compression/zstd/zstd.hpp" #include "zstd.h" /* @@ -31,12 +33,6 @@ Data layout per segment: +--------------------------------------------+ */ -using page_id_t = int64_t; -using page_offset_t = uint32_t; -using uncompressed_size_t = uint64_t; -using compressed_size_t = uint64_t; -using string_length_t = uint32_t; - static int32_t GetCompressionLevel() { return duckdb_zstd::ZSTD_defaultCLevel(); } @@ -122,7 +118,7 @@ struct ZSTDAnalyzeState : public AnalyzeState { public: DBConfig &config; - duckdb_zstd::ZSTD_CCtx *context; + duckdb_zstd::ZSTD_CCtx *context = nullptr; //! The combined string lengths for all values in the segment idx_t total_size = 0; //! The total amount of values in the segment @@ -198,12 +194,15 @@ idx_t ZSTDStorage::StringFinalAnalyze(AnalyzeState &state_p) { if (state.values_in_vector) { D_ASSERT(state.values_in_vector < ZSTD_VECTOR_SIZE); + state.vectors_in_segment++; + } + if (state.vectors_in_segment) { state.segment_count++; } double penalty; idx_t average_length = state.total_size / state.count; - auto threshold = state.config.options.zstd_min_string_length; + auto threshold = Settings::Get(state.config); if (average_length >= threshold) { penalty = 1.0; } else { @@ -234,81 +233,84 @@ class ZSTDCompressionState : public CompressionState { : CompressionState(analyze_state_p->info), analyze_state(std::move(analyze_state_p)), checkpoint_data(checkpoint_data), partial_block_manager(checkpoint_data.GetCheckpointState().GetPartialBlockManager()), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_ZSTD)) { - total_vector_count = GetVectorCount(analyze_state->count); - total_segment_count = analyze_state->segment_count; - vectors_per_segment = analyze_state->vectors_per_segment; - + function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_ZSTD)), + total_tuple_count(analyze_state->count), total_vector_count(GetVectorCount(total_tuple_count)), + total_segment_count(analyze_state->segment_count), vectors_per_segment(analyze_state->vectors_per_segment) { segment_count = 0; vector_count = 0; - vector_in_segment_count = 0; - tuple_count = 0; + vector_state.tuple_count = 0; - idx_t offset = NewSegment(); - SetCurrentBuffer(segment_handle); - current_buffer_ptr = segment_handle.Ptr() + offset; - D_ASSERT(GetCurrentOffset() <= GetWritableSpace(info)); + NewSegment(); + if (!(buffer_collection.GetCurrentOffset() <= GetWritableSpace(info))) { + throw InternalException( + "(ZSTDCompressionState::ZSTDCompressionState) Offset (%d) exceeds writable space! (%d)", + buffer_collection.GetCurrentOffset(), GetWritableSpace(info)); + } } public: void ResetOutBuffer() { - D_ASSERT(GetCurrentOffset() <= GetWritableSpace(info)); - out_buffer.dst = current_buffer_ptr; + if (!(buffer_collection.GetCurrentOffset() <= GetWritableSpace(info))) { + throw InternalException("(ZSTDCompressionState::ResetOutBuffer) Offset (%d) exceeds writable space! (%d)", + buffer_collection.GetCurrentOffset(), GetWritableSpace(info)); + } + out_buffer.dst = buffer_collection.GetCurrentBufferPtr(); out_buffer.pos = 0; - auto remaining_space = info.GetBlockSize() - GetCurrentOffset() - sizeof(block_id_t); + auto remaining_space = info.GetBlockSize() - buffer_collection.GetCurrentOffset() - sizeof(block_id_t); out_buffer.size = remaining_space; } - void SetCurrentBuffer(BufferHandle &handle) { - current_buffer = &handle; - current_buffer_ptr = handle.Ptr(); + void WriteBlockIdPointer(page_id_t block_id) { + auto ptr = buffer_collection.GetCurrentBufferPtr(); + Store(block_id, ptr); + buffer_collection.GetCurrentOffset() += sizeof(block_id_t); } - BufferHandle &GetExtraPageBuffer(block_id_t current_block_id) { + void GetExtraPageBuffer(block_id_t current_block_id) { auto &block_manager = partial_block_manager.GetBlockManager(); auto &buffer_manager = block_manager.buffer_manager; - optional_ptr to_use; - - if (in_vector) { - // Currently in a Vector, we have to be mindful of the buffer that the string_lengths lives on - // as that will have to stay writable until the Vector is finished - bool already_separated = current_buffer != vector_lengths_buffer; - if (already_separated) { - // Already separated, can keep using the other buffer (flush it first) - FlushPage(*current_buffer, current_block_id); - to_use = current_buffer; - } else { - // Not already separated, have to use the other page - to_use = current_buffer == &extra_pages[0] ? &extra_pages[1] : &extra_pages[0]; - } - } else { - // Start of a new Vector, the string_lengths did not fit on the previous page - bool previous_page_is_segment = current_buffer == &segment_handle; - if (!previous_page_is_segment) { - // We're asking for a fresh buffer to start the vectors data - // that means the previous vector is finished - so we can flush the current page and reuse it - D_ASSERT(current_block_id != INVALID_BLOCK); - FlushPage(*current_buffer, current_block_id); - to_use = current_buffer; - } else { - // Previous buffer was the segment, take the first extra page in this case - to_use = &extra_pages[0]; - } + auto ¤t_buffer_state = buffer_collection.GetCurrentBufferState(); + current_buffer_state.full = true; + + if (buffer_collection.CanFlush()) { + auto &buffer_state = buffer_collection.GetCurrentBufferState(); + FlushPage(buffer_collection.BufferHandleMutable(), current_block_id); + buffer_state.flags.Clear(); + buffer_state.full = false; + buffer_state.offset = 0; + return; } - if (!to_use->IsValid()) { - *to_use = buffer_manager.Allocate(MemoryTag::OVERFLOW_STRINGS, &block_manager); + //! Cycle through the extra pages, to figure out which one we can use + //! In the worst case, the segment handle is entirely filled with vector metadata + //! The last part of the first extra page is entirely filled with string metadata + //! So we can only use the second extra page for data + auto buffer_data = buffer_collection.GetBufferData(/*include_segment = */ false); + for (auto &buffer : buffer_data) { + auto &buffer_state = buffer.state; + auto &flags = buffer_state.flags; + if (flags.HasStringMetadata() || buffer_state.full) { + continue; + } + buffer_collection.SetCurrentBuffer(buffer.slot); + auto &buffer_handle = buffer_collection.BufferHandleMutable(); + if (!buffer_handle.IsValid()) { + buffer_handle = buffer_manager.Allocate(MemoryTag::OVERFLOW_STRINGS, &block_manager); + } + return; } - return *to_use; + throw InternalException( + "(ZSTDCompressionState::GetExtraPageBuffer) Wasn't able to find a buffer to write overflow data to!"); } - idx_t NewSegment() { - if (current_buffer == &segment_handle) { + void NewSegment() { + if (buffer_collection.IsOnSegmentBuffer()) { // This should never happen, the string lengths + vector metadata size should always exceed a page size, // even if the strings are all empty - throw InternalException("We are asking for a new segment, but somehow we're still writing vector data onto " + throw InternalException("(ZSTDCompressionState::NewSegment) We are asking for a new segment, but somehow " + "we're still writing vector data onto " "the initial (segment) page"); } FlushSegment(); @@ -317,65 +319,56 @@ class ZSTDCompressionState : public CompressionState { // Figure out how many vectors we are storing in this segment idx_t vectors_in_segment; if (segment_count + 1 >= total_segment_count) { - vectors_in_segment = total_vector_count - vector_count; + vectors_in_segment = total_vector_count - (segment_count * vectors_per_segment); } else { vectors_in_segment = vectors_per_segment; } - idx_t offset = 0; - page_ids = reinterpret_cast(segment_handle.Ptr() + offset); - offset += (sizeof(page_id_t) * vectors_in_segment); - - offset = AlignValue(offset); - page_offsets = reinterpret_cast(segment_handle.Ptr() + offset); - offset += (sizeof(page_offset_t) * vectors_in_segment); - - offset = AlignValue(offset); - uncompressed_sizes = reinterpret_cast(segment_handle.Ptr() + offset); - offset += (sizeof(uncompressed_size_t) * vectors_in_segment); - - offset = AlignValue(offset); - compressed_sizes = reinterpret_cast(segment_handle.Ptr() + offset); - offset += (sizeof(compressed_size_t) * vectors_in_segment); - - D_ASSERT(offset == GetVectorMetadataSize(vectors_in_segment)); - return offset; + buffer_collection.SetCurrentBuffer(ZSTDCompressionBufferCollection::Slot::SEGMENT); + buffer_collection.buffer_states[0].flags.SetVectorMetadata(); + segment_state.InitializeSegment(buffer_collection, vectors_in_segment); + if (!(buffer_collection.GetCurrentOffset() <= GetWritableSpace(info))) { + throw InternalException("(ZSTDCompressionState::NewSegment) Offset (%d) exceeds writable space! (%d)", + buffer_collection.GetCurrentOffset(), GetWritableSpace(info)); + } } void InitializeVector() { - D_ASSERT(!in_vector); + D_ASSERT(!vector_state.in_vector); + idx_t expected_tuple_count; if (vector_count + 1 >= total_vector_count) { //! Last vector - vector_size = analyze_state->count - (ZSTD_VECTOR_SIZE * vector_count); + expected_tuple_count = analyze_state->count - (ZSTD_VECTOR_SIZE * vector_count); } else { - vector_size = ZSTD_VECTOR_SIZE; + expected_tuple_count = ZSTD_VECTOR_SIZE; } - auto current_offset = GetCurrentOffset(); - current_offset = UnsafeNumericCast( - AlignValue(UnsafeNumericCast(current_offset))); - current_buffer_ptr = current_buffer->Ptr() + current_offset; - D_ASSERT(GetCurrentOffset() <= GetWritableSpace(info)); - compressed_size = 0; - uncompressed_size = 0; - - if (GetVectorMetadataSize(vector_in_segment_count + 1) > GetWritableSpace(info)) { - D_ASSERT(vector_in_segment_count <= vectors_per_segment); - // Can't fit this vector on this segment anymore, have to flush and a grab new one + buffer_collection.AlignCurrentOffset(); + if (!(buffer_collection.GetCurrentOffset() <= GetWritableSpace(info))) { + throw InternalException("(ZSTDCompressionState::InitializeVector) Offset (%d) exceeds writable space! (%d)", + buffer_collection.GetCurrentOffset(), GetWritableSpace(info)); + } + vector_state.compressed_size = 0; + vector_state.uncompressed_size = 0; + vector_state.string_lengths = nullptr; + vector_state.tuple_count = 0; + vector_state.vector_size = 0; + vector_state.starting_page = 0XDEADBEEF; + vector_state.starting_offset = 0XDEADBEEF; + + if (segment_state.vector_in_segment_count + 1 > segment_state.total_vectors_in_segment) { + //! Last vector in the segment NewSegment(); } - if (current_offset + (vector_size * sizeof(string_length_t)) >= GetWritableSpace(info)) { + if (buffer_collection.GetCurrentOffset() + (expected_tuple_count * sizeof(string_length_t)) >= + GetWritableSpace(info)) { // Check if there is room on the current page for the vector data NewPage(); } - current_offset = GetCurrentOffset(); - starting_offset = current_offset; - starting_page = GetCurrentId(); - - vector_lengths_buffer = current_buffer; - string_lengths = reinterpret_cast(current_buffer->Ptr() + current_offset); - current_buffer_ptr = reinterpret_cast(string_lengths); - current_buffer_ptr += vector_size * sizeof(string_length_t); + + buffer_collection.AlignCurrentOffset(); + vector_state.Initialize(expected_tuple_count, buffer_collection, info); + // 'out_buffer' should be set to point directly after the string_lengths ResetOutBuffer(); @@ -384,7 +377,7 @@ class ZSTDCompressionState : public CompressionState { duckdb_zstd::ZSTD_CCtx_refCDict(analyze_state->context, nullptr); duckdb_zstd::ZSTD_CCtx_setParameter(analyze_state->context, duckdb_zstd::ZSTD_c_compressionLevel, GetCompressionLevel()); - in_vector = true; + vector_state.in_vector = true; } void CompressString(const string_t &string, bool end_of_vector) { @@ -395,7 +388,7 @@ class ZSTDCompressionState : public CompressionState { if (!end_of_vector && string.GetSize() == 0) { return; } - uncompressed_size += string.GetSize(); + vector_state.uncompressed_size += string.GetSize(); const auto end_mode = end_of_vector ? duckdb_zstd::ZSTD_e_end : duckdb_zstd::ZSTD_e_continue; size_t compress_result; @@ -406,14 +399,18 @@ class ZSTDCompressionState : public CompressionState { duckdb_zstd::ZSTD_compressStream2(analyze_state->context, &out_buffer, &in_buffer, end_mode); D_ASSERT(out_buffer.pos >= old_pos); auto diff = out_buffer.pos - old_pos; - compressed_size += diff; - current_buffer_ptr += diff; + vector_state.compressed_size += diff; + buffer_collection.GetCurrentOffset() += diff; if (duckdb_zstd::ZSTD_isError(compress_result)) { throw InvalidInputException("ZSTD Compression failed: %s", duckdb_zstd::ZSTD_getErrorName(compress_result)); } - D_ASSERT(GetCurrentOffset() <= GetWritableSpace(info)); + if (!(buffer_collection.GetCurrentOffset() <= GetWritableSpace(info))) { + throw InternalException( + "(ZSTDCompressionState::CompressString) Offset (%d) exceeds writable space! (%d)", + buffer_collection.GetCurrentOffset(), GetWritableSpace(info)); + } if (compress_result == 0) { // Finished break; @@ -423,16 +420,13 @@ class ZSTDCompressionState : public CompressionState { } void AddStringInternal(const string_t &string) { - if (!tuple_count) { + if (!vector_state.tuple_count) { InitializeVector(); } - string_lengths[tuple_count] = UnsafeNumericCast(string.GetSize()); - bool final_tuple = tuple_count + 1 >= vector_size; - CompressString(string, final_tuple); - - tuple_count++; - if (tuple_count == vector_size) { + auto is_final_string = vector_state.AddStringLength(string); + CompressString(string, is_final_string); + if (is_final_string) { // Reached the end of this vector FlushVector(); } @@ -440,15 +434,14 @@ class ZSTDCompressionState : public CompressionState { void AddString(const string_t &string) { AddStringInternal(string); - UncompressedStringStorage::UpdateStringStats(segment->stats, string); + UncompressedStringStorage::UpdateStringStats(buffer_collection.segment->stats, string); } void NewPage(bool additional_data_page = false) { block_id_t new_id = FinalizePage(); - block_id_t current_block_id = block_id; - auto &buffer = GetExtraPageBuffer(current_block_id); - block_id = new_id; - SetCurrentBuffer(buffer); + block_id_t current_block_id = buffer_collection.GetCurrentId(); + GetExtraPageBuffer(current_block_id); + buffer_collection.block_id = new_id; ResetOutBuffer(); } @@ -456,14 +449,15 @@ class ZSTDCompressionState : public CompressionState { auto &block_manager = partial_block_manager.GetBlockManager(); auto new_id = partial_block_manager.GetFreeBlockId(); - auto &state = segment->GetSegmentState()->Cast(); + auto &state = buffer_collection.segment->GetSegmentState()->Cast(); state.RegisterBlock(block_manager, new_id); - D_ASSERT(GetCurrentOffset() <= GetWritableSpace(info)); + auto &buffer_state = buffer_collection.GetCurrentBufferState(); + buffer_state.full = true; // Write the new id at the end of the last page - Store(new_id, current_buffer_ptr); - current_buffer_ptr += sizeof(block_id_t); + WriteBlockIdPointer(new_id); + D_ASSERT(buffer_state.offset <= info.GetBlockSize()); return new_id; } @@ -479,46 +473,63 @@ class ZSTDCompressionState : public CompressionState { void FlushVector() { // Write the metadata for this Vector - page_ids[vector_in_segment_count] = starting_page; - page_offsets[vector_in_segment_count] = starting_offset; - compressed_sizes[vector_in_segment_count] = compressed_size; - uncompressed_sizes[vector_in_segment_count] = uncompressed_size; + segment_state.page_ids[segment_state.vector_in_segment_count] = vector_state.starting_page; + segment_state.page_offsets[segment_state.vector_in_segment_count] = vector_state.starting_offset; + segment_state.compressed_sizes[segment_state.vector_in_segment_count] = vector_state.compressed_size; + segment_state.uncompressed_sizes[segment_state.vector_in_segment_count] = vector_state.uncompressed_size; + if (segment_state.vector_in_segment_count >= segment_state.total_vectors_in_segment) { + throw InternalException( + "(ZSTDCompressionState::FlushVector) Written too many vectors (%d) to this segment! (expected: %d)", + segment_state.vector_in_segment_count, segment_state.total_vectors_in_segment); + } vector_count++; - vector_in_segment_count++; - in_vector = false; - segment->count += tuple_count; - - const bool is_last_vector = vector_count == total_vector_count; - tuple_count = 0; - if (is_last_vector) { - FlushPage(*current_buffer, block_id); - if (starting_page != block_id) { - FlushPage(*vector_lengths_buffer, starting_page); - } - } else { - if (vector_lengths_buffer == current_buffer) { - // We did not cross a page boundary writing this vector - return; + segment_state.vector_in_segment_count++; + vector_state.in_vector = false; + buffer_collection.segment->count += vector_state.tuple_count; + + vector_state.tuple_count = 0; + + //! If the string lengths live on an overflow page, and that buffer is full + //! then we want to flush it + + auto buffer_data = buffer_collection.GetBufferData(/*include_segment=*/true); + ZSTDCompressionBufferCollection::Slot slot = ZSTDCompressionBufferCollection::Slot::SEGMENT; + optional_ptr buffer_handle_ptr; + optional_ptr buffer_state_ptr; + for (auto &buffer : buffer_data) { + auto &buffer_state = buffer.state; + if (buffer_state.flags.HasStringMetadata()) { + if (buffer_handle_ptr) { + throw InternalException("(ZSTDCompressionState::FlushVector) Multiple buffers (%d and %d) have " + "string metadata on them, this is impossible and indicates a bug!", + static_cast(slot), static_cast(buffer.slot)); + } + slot = buffer.slot; + buffer_state_ptr = buffer.state; + buffer_handle_ptr = buffer.handle; } - // Flush the page that holds the vector lengths - FlushPage(*vector_lengths_buffer, starting_page); + buffer_state.flags.UnsetStringMetadata(); + buffer_state.flags.UnsetData(); } - } - page_id_t GetCurrentId() { - if (&segment_handle == current_buffer.get()) { - return INVALID_BLOCK; + if (!buffer_handle_ptr) { + throw InternalException("(ZSTDCompressionState::FlushVector) None of the buffers have string metadata on " + "them, this is impossible and indicates a bug!"); } - return block_id; - } - - page_offset_t GetCurrentOffset() { - auto &handle = *current_buffer; - auto start_of_buffer = handle.Ptr(); - D_ASSERT(current_buffer_ptr >= start_of_buffer); - auto res = (page_offset_t)(current_buffer_ptr - start_of_buffer); - D_ASSERT(res <= GetWritableSpace(info)); - return res; + if (slot == ZSTDCompressionBufferCollection::Slot::SEGMENT) { + //! This is the segment handle, we don't need to flush that here, it'll get flushed when the segment is done + return; + } + auto &buffer_state = *buffer_state_ptr; + if (!buffer_state.full) { + //! It contains the string metadata of the current vector, but the buffer isn't full + //! so we don't need to flush it yet + return; + } + auto &buffer_handle = *buffer_handle_ptr; + FlushPage(buffer_handle, vector_state.starting_page); + buffer_state.offset = 0; + buffer_state.full = false; } void CreateEmptySegment() { @@ -526,40 +537,67 @@ class ZSTDCompressionState : public CompressionState { auto &type = checkpoint_data.GetType(); auto compressed_segment = ColumnSegment::CreateTransientSegment(db, function, type, info.GetBlockSize(), info.GetBlockManager()); - segment = std::move(compressed_segment); + buffer_collection.segment = std::move(compressed_segment); auto &buffer_manager = BufferManager::GetBufferManager(checkpoint_data.GetDatabase()); - segment_handle = buffer_manager.Pin(segment->block); + buffer_collection.segment_handle = buffer_manager.Pin(buffer_collection.segment->block); } void FlushSegment() { - if (!segment) { + if (!buffer_collection.segment) { return; } - auto &state = checkpoint_data.GetCheckpointState(); - idx_t segment_block_size; + if (segment_state.vector_in_segment_count != segment_state.total_vectors_in_segment) { + throw InternalException("(ZSTDCompressionState::FlushSegment) We haven't written all vectors that we were " + "expecting to write (%d instead of %d)!", + segment_state.vector_in_segment_count, segment_state.total_vectors_in_segment); + } - if (current_buffer.get() == &segment_handle) { - segment_block_size = GetCurrentOffset(); - } else { - // Block is fully used - segment_block_size = info.GetBlockSize(); + auto &segment_buffer_state = buffer_collection.buffer_states[0]; + auto segment_block_size = segment_buffer_state.offset; + if (segment_block_size < GetVectorMetadataSize(segment_state.total_vectors_in_segment)) { + throw InternalException( + "(ZSTDCompressionState::FlushSegment) Expected offset to be at least %d, but found %d instead", + GetVectorMetadataSize(segment_state.total_vectors_in_segment), segment_block_size); + } + + bool seen_dirty_buffer = false; + auto buffer_data = buffer_collection.GetBufferData(/*include_segment=*/false); + for (auto &buffer : buffer_data) { + auto &buffer_state = buffer.state; + auto &buffer_handle = buffer.handle; + if (buffer_state.offset != 0) { + if (seen_dirty_buffer) { + throw InternalException("(ZSTDCompressionState::FlushSegment) Both extra pages were dirty (needed " + "to be flushed), this should be impossible"); + } + FlushPage(buffer_handle, buffer_collection.block_id); + buffer_state.full = false; + buffer_state.offset = 0; + buffer_state.flags.Clear(); + seen_dirty_buffer = true; + } } - state.FlushSegment(std::move(segment), std::move(segment_handle), segment_block_size); + auto &state = checkpoint_data.GetCheckpointState(); + state.FlushSegment(std::move(buffer_collection.segment), std::move(buffer_collection.segment_handle), + segment_block_size); + segment_buffer_state.flags.Clear(); + segment_buffer_state.full = true; + segment_buffer_state.offset = 0; segment_count++; - vector_in_segment_count = 0; } void Finalize() { - D_ASSERT(!tuple_count); + D_ASSERT(!vector_state.tuple_count); FlushSegment(); - segment.reset(); + buffer_collection.segment.reset(); } void AddNull() { - segment->stats.statistics.SetHasNullFast(); - AddStringInternal(""); + buffer_collection.segment->stats.statistics.SetHasNullFast(); + string_t empty(static_cast(0)); + AddStringInternal(empty); } public: @@ -568,56 +606,30 @@ class ZSTDCompressionState : public CompressionState { PartialBlockManager &partial_block_manager; CompressionFunction &function; - // The segment state - //! Current segment index we're at - idx_t segment_count = 0; + //! --- Analyzed Data --- + //! The amount of tuples we're writing + const idx_t total_tuple_count; + //! The amount of vectors we're writing + const idx_t total_vector_count; //! The total amount of segments we're writing - idx_t total_segment_count = 0; - //! The vectors to store in the last segment - idx_t vectors_in_last_segment = 0; + const idx_t total_segment_count; //! The vectors to store in a segment (not the last one) - idx_t vectors_per_segment = 0; - unique_ptr segment; - BufferHandle segment_handle; - - // Non-segment buffers - BufferHandle extra_pages[2]; - block_id_t block_id = INVALID_BLOCK; + const idx_t vectors_per_segment; - // Current block state - optional_ptr current_buffer; - //! The buffer that contains the vector lengths - optional_ptr vector_lengths_buffer; - data_ptr_t current_buffer_ptr; - - //===--------------------------------------------------------------------===// - // Vector metadata - //===--------------------------------------------------------------------===// - page_id_t starting_page; - page_offset_t starting_offset; - - page_id_t *page_ids; - page_offset_t *page_offsets; - uncompressed_size_t *uncompressed_sizes; - compressed_size_t *compressed_sizes; //! The amount of vectors we've seen so far idx_t vector_count = 0; - //! The amount of vectors we've seen in the current segment - idx_t vector_in_segment_count = 0; - //! The amount of vectors we're writing - idx_t total_vector_count = 0; - //! Whether we are currently in a Vector - bool in_vector = false; + //! Current segment index we're at + idx_t segment_count = 0; + + ZSTDCompressionBufferCollection buffer_collection; + //! The compression context indicating where we are in the output buffer duckdb_zstd::ZSTD_outBuffer out_buffer; - idx_t uncompressed_size = 0; - idx_t compressed_size = 0; - string_length_t *string_lengths; - //! Amount of tuples we have seen for the current vector - idx_t tuple_count = 0; - //! The expected size of this vector (ZSTD_VECTOR_SIZE except for the last one) - idx_t vector_size; + //! State of the current Vector we are writing + ZSTDCompressionVectorState vector_state; + //! State of the current Segment we are writing + ZSTDCompressionSegmentState segment_state; }; unique_ptr ZSTDStorage::InitCompression(ColumnDataCheckpointData &checkpoint_data, @@ -637,7 +649,7 @@ void ZSTDStorage::Compress(CompressionState &state_p, Vector &input, idx_t count for (idx_t i = 0; i < count; i++) { auto idx = vdata.sel->get_index(i); // Note: we treat nulls and empty strings the same - if (!vdata.validity.RowIsValid(idx) || data[idx].GetSize() == 0) { + if (!vdata.validity.RowIsValid(idx)) { state.AddNull(); continue; } @@ -694,7 +706,7 @@ struct ZSTDScanState : public SegmentScanState { public: explicit ZSTDScanState(ColumnSegment &segment) : state(segment.GetSegmentState()->Cast()), - block_manager(segment.GetBlockManager()), buffer_manager(BufferManager::GetBufferManager(segment.db)), + block_manager(segment.block->GetBlockManager()), buffer_manager(BufferManager::GetBufferManager(segment.db)), segment_block_offset(segment.GetBlockOffset()), segment(segment) { decompression_context = duckdb_zstd::ZSTD_createDCtx(); segment_handle = buffer_manager.Pin(segment.block); diff --git a/src/duckdb/src/storage/data_pointer.cpp b/src/duckdb/src/storage/data_pointer.cpp index 969c8484b..8e13bbccf 100644 --- a/src/duckdb/src/storage/data_pointer.cpp +++ b/src/duckdb/src/storage/data_pointer.cpp @@ -31,7 +31,8 @@ unique_ptr ColumnSegmentState::Deserialize(Deserializer &des auto &db = deserializer.Get(); auto &type = deserializer.Get(); - auto compression_function = DBConfig::GetConfig(db).GetCompressionFunction(compression_type, type.InternalType()); + auto compression_function = + DBConfig::GetConfig(db).TryGetCompressionFunction(compression_type, type.InternalType()); if (!compression_function || !compression_function->deserialize_state) { throw SerializationException("Deserializing a ColumnSegmentState but could not find deserialize method"); } diff --git a/src/duckdb/src/storage/data_table.cpp b/src/duckdb/src/storage/data_table.cpp index feb1e835f..019ca3f7c 100644 --- a/src/duckdb/src/storage/data_table.cpp +++ b/src/duckdb/src/storage/data_table.cpp @@ -45,6 +45,17 @@ bool DataTableInfo::IsTemporary() const { return db.IsTemporary(); } +IndexStorageInfo DataTableInfo::ExtractIndexStorageInfo(const string &name) { + for (idx_t i = 0; i < index_storage_infos.size(); i++) { + if (index_storage_infos[i].name == name) { + auto result = std::move(index_storage_infos[i]); + index_storage_infos.erase_at(i); + return result; + } + } + throw InternalException("ExtractIndexStorageInfo: index storage info with name '%s' not found", name); +} + DataTable::DataTable(AttachedDatabase &db, shared_ptr table_io_manager_p, const string &schema, const string &table, vector column_definitions_p, unique_ptr data) @@ -103,7 +114,7 @@ DataTable::DataTable(ClientContext &context, DataTable &parent, idx_t removed_co info->BindIndexes(context); // first check if there are any indexes that exist that point to the removed column - info->indexes.Scan([&](Index &index) { + for (auto &index : info->indexes.Indexes()) { for (auto &column_id : index.GetColumnIds()) { if (column_id == removed_column) { throw CatalogException("Cannot drop this column: an index depends on it!"); @@ -111,8 +122,7 @@ DataTable::DataTable(ClientContext &context, DataTable &parent, idx_t removed_co throw CatalogException("Cannot drop this column: an index depends on a column after it!"); } } - return false; - }); + } // erase the column definitions from this DataTable D_ASSERT(removed_column < column_definitions.size()); @@ -172,14 +182,13 @@ DataTable::DataTable(ClientContext &context, DataTable &parent, idx_t changed_id info->BindIndexes(context); // first check if there are any indexes that exist that point to the changed column - info->indexes.Scan([&](Index &index) { + for (auto &index : info->indexes.Indexes()) { for (auto &column_id : index.GetColumnIds()) { if (column_id == changed_idx) { throw CatalogException("Cannot change the type of this column: an index depends on it!"); } } - return false; - }); + } // change the type in this DataTable column_definitions[changed_idx].SetType(target_type); @@ -319,15 +328,12 @@ bool DataTable::HasUniqueIndexes() const { if (!HasIndexes()) { return false; } - bool has_unique_index = false; - info->indexes.Scan([&](Index &index) { + for (auto &index : info->indexes.Indexes()) { if (index.IsUnique()) { - has_unique_index = true; return true; } - return false; - }); - return has_unique_index; + } + return false; } void DataTable::AddIndex(unique_ptr index) { @@ -344,12 +350,11 @@ void DataTable::SetIndexStorageInfo(vector index_storage_info) } void DataTable::VacuumIndexes() { - info->indexes.Scan([&](Index &index) { + for (auto &index : info->indexes.Indexes()) { if (index.IsBound()) { index.Cast().Vacuum(); } - return false; - }); + } } void DataTable::VerifyIndexBuffers() { @@ -357,7 +362,7 @@ void DataTable::VerifyIndexBuffers() { } void DataTableInfo::VerifyIndexBuffers() { - indexes.ScanEntries([&](IndexEntry &entry) { + for (auto &entry : indexes.IndexEntries()) { auto &index = *entry.index; if (index.IsBound()) { index.Cast().VerifyBuffers(); @@ -365,8 +370,7 @@ void DataTableInfo::VerifyIndexBuffers() { if (entry.deleted_rows_in_use) { entry.deleted_rows_in_use->VerifyBuffers(); } - return false; - }); + } } void DataTable::CleanupAppend(transaction_t lowest_transaction, idx_t start, idx_t count) { @@ -402,15 +406,14 @@ void DataTable::SetTableName(string new_name) { TableStorageInfo DataTable::GetStorageInfo() { TableStorageInfo result; result.cardinality = GetTotalRows(); - info->indexes.Scan([&](Index &index) { + for (auto &index : info->indexes.Indexes()) { IndexInfo index_info; index_info.is_primary = index.IsPrimary(); index_info.is_unique = index.IsUnique() || index_info.is_primary; index_info.is_foreign = index.IsForeign(); index_info.column_set = index.GetColumnIdSet(); result.index_info.push_back(std::move(index_info)); - return false; - }); + } return result; } @@ -685,10 +688,10 @@ void DataTable::VerifyUniqueIndexes(TableIndexList &indexes, optional_ptr manager) { // Verify the constraint without a conflict manager. if (!manager) { - return indexes.ScanEntries([&](IndexEntry &entry) { + for (auto &entry : indexes.IndexEntries()) { auto &index = *entry.index; if (!index.IsUnique() || index.GetIndexType() != ART::TYPE_NAME) { - return false; + continue; } D_ASSERT(index.IsBound()); auto &art = index.Cast(); @@ -705,20 +708,20 @@ void DataTable::VerifyUniqueIndexes(TableIndexList &indexes, optional_ptrGetConflictInfo(); // Find all indexes matching the conflict target. - indexes.Scan([&](Index &index) { + for (auto &index : indexes.Indexes()) { if (!index.IsUnique() || index.GetIndexType() != ART::TYPE_NAME) { - return false; + continue; } if (!conflict_info.ConflictTargetMatches(index)) { - return false; + continue; } D_ASSERT(index.IsBound()); auto &art = index.Cast(); @@ -729,8 +732,7 @@ void DataTable::VerifyUniqueIndexes(TableIndexList &indexes, optional_ptrAddIndex(art, nullptr); } - return false; - }); + } // Verify indexes matching the conflict target. manager->SetMode(ConflictManagerMode::SCAN); @@ -743,12 +745,12 @@ void DataTable::VerifyUniqueIndexes(TableIndexList &indexes, optional_ptrSetMode(ConflictManagerMode::THROW); - indexes.Scan([&](Index &index) { + for (auto &index : indexes.Indexes()) { if (!index.IsUnique() || index.GetIndexType() != ART::TYPE_NAME) { - return false; + continue; } if (manager->IndexMatches(index.Cast())) { - return false; + continue; } D_ASSERT(index.IsBound()); auto &art = index.Cast(); @@ -761,8 +763,7 @@ void DataTable::VerifyUniqueIndexes(TableIndexList &indexes, optional_ptr commit_state) { +void DataTable::MergeStorage(RowGroupCollection &data, optional_ptr commit_state) { row_groups->MergeStorage(data, this, commit_state); row_groups->Verify(); } @@ -1179,7 +1179,7 @@ void DataTable::RevertAppend(DuckTransaction &transaction, idx_t start_row, idx_ for (idx_t i = 0; i < chunk.size(); i++) { row_data[i] = NumericCast(current_row_base + i); } - info->indexes.ScanEntries([&](IndexEntry &entry) { + for (auto &entry : info->indexes.IndexEntries()) { lock_guard guard(entry.lock); auto &index = *entry.index; optional_ptr remove_index; @@ -1188,25 +1188,23 @@ void DataTable::RevertAppend(DuckTransaction &transaction, idx_t start_row, idx_ } else { if (!index.IsBound()) { // We cannot add to unbound indexes, so there is no need to revert them. - return false; + continue; } remove_index = index.Cast(); } remove_index->Delete(chunk, row_identifiers); - return false; - }); + } current_row_base += chunk.size(); }); } #ifdef DEBUG // Verify that our index memory is stable. - info->indexes.Scan([&](Index &index) { + for (auto &index : info->indexes.Indexes()) { if (index.IsBound()) { index.Cast().VerifyBuffers(); } - return false; - }); + } #endif // revert the data table append @@ -1229,14 +1227,14 @@ ErrorData DataTable::AppendToIndexes(TableIndexList &indexes, optional_ptr guard(entry.lock); auto &index = *entry.index; if (!index.IsBound()) { // Buffer only the key columns, and store their mapping. auto &unbound_index = index.Cast(); unbound_index.BufferChunk(index_chunk, row_ids, mapped_column_ids, BufferedIndexReplay::INSERT_ENTRY); - return false; + continue; } auto &bound_index = index.Cast(); @@ -1295,12 +1293,11 @@ ErrorData DataTable::AppendToIndexes(TableIndexList &indexes, optional_ptr
indexes.Scan([&](Index &index) { + for (auto &index : info->indexes.Indexes()) { auto &main_index = index.Cast(); main_index.Delete(chunk, row_identifiers); - return false; - }); + } } void DataTable::RemoveFromIndexes(const QueryContext &context, Vector &row_identifiers, idx_t count, @@ -1553,11 +1549,10 @@ void DataTable::VerifyUpdateConstraints(ConstraintState &state, ClientContext &c #ifdef DEBUG // Ensure that we never call UPDATE for indexed columns. // Instead, we must rewrite these updates into DELETE + INSERT. - info->indexes.Scan([&](Index &index) { + for (auto &index : info->indexes.Indexes()) { D_ASSERT(index.IsBound()); D_ASSERT(!index.Cast().IndexIsUpdated(column_ids)); - return false; - }); + } #endif } @@ -1711,11 +1706,10 @@ void DataTable::CommitDropTable() { row_groups->CommitDropTable(); // propagate dropping this table to its indexes: frees all index memory - info->indexes.Scan([&](Index &index) { + for (auto &index : info->indexes.Indexes()) { D_ASSERT(index.IsBound()); index.Cast().CommitDrop(); - return false; - }); + } } //===--------------------------------------------------------------------===// @@ -1729,7 +1723,7 @@ vector DataTable::GetColumnSegmentInfo(const QueryContext &co // Index Constraint Creation //===--------------------------------------------------------------------===// void DataTable::AddIndex(const ColumnList &columns, const vector &column_indexes, - const IndexConstraintType type, const IndexStorageInfo &index_info) { + const IndexConstraintType type, IndexStorageInfo index_info) { if (!IsMainTable()) { throw TransactionException("Transaction conflict: attempting to add an index to table \"%s\" but it has been " "%s by a different transaction", diff --git a/src/duckdb/src/storage/external_file_cache.cpp b/src/duckdb/src/storage/external_file_cache.cpp index 304116c7f..0a5a04963 100644 --- a/src/duckdb/src/storage/external_file_cache.cpp +++ b/src/duckdb/src/storage/external_file_cache.cpp @@ -39,7 +39,7 @@ ExternalFileCache::CachedFileRange::GetOverlap(const CachedFileRange &other) con void ExternalFileCache::CachedFileRange::AddCheckSum() { #ifdef DEBUG D_ASSERT(checksum == 0); - auto buffer_handle = block_handle->block_manager.buffer_manager.Pin(block_handle); + auto buffer_handle = block_handle->GetMemory().GetBufferManager().Pin(block_handle); checksum = Checksum(buffer_handle.Ptr(), nr_bytes); #endif } @@ -49,7 +49,7 @@ void ExternalFileCache::CachedFileRange::VerifyCheckSum() { if (checksum == 0) { return; } - auto buffer_handle = block_handle->block_manager.buffer_manager.Pin(block_handle); + auto buffer_handle = block_handle->GetMemory().GetBufferManager().Pin(block_handle); if (!buffer_handle.IsValid()) { return; } @@ -153,7 +153,8 @@ vector ExternalFileCache::GetCachedFileInformation() cons auto ranges_guard = file.second->lock.GetSharedLock(); for (const auto &range_entry : file.second->Ranges(ranges_guard)) { const auto &range = *range_entry.second; - result.push_back({file.first, range.nr_bytes, range.location, !range.block_handle->IsUnloaded()}); + result.push_back( + {file.first, range.nr_bytes, range.location, !range.block_handle->GetMemory().IsUnloaded()}); } } return result; diff --git a/src/duckdb/src/storage/external_file_cache_util.cpp b/src/duckdb/src/storage/external_file_cache_util.cpp index 08da502f9..deae15af2 100644 --- a/src/duckdb/src/storage/external_file_cache_util.cpp +++ b/src/duckdb/src/storage/external_file_cache_util.cpp @@ -34,12 +34,11 @@ CacheValidationMode ExternalFileCacheUtil::GetCacheValidationMode(const OpenFile // If client context is available, check client-local settings first, then fall back to database config. if (client_context) { - return DBConfig::GetSetting(*client_context); + return Settings::Get(*client_context); } // No client context, fall back to database config. - auto &config = DBConfig::GetConfig(db); - return config.options.validate_external_file_cache; + return Settings::Get(db); } } // namespace duckdb diff --git a/src/duckdb/src/storage/local_storage.cpp b/src/duckdb/src/storage/local_storage.cpp index f44c9ed9c..be434cbf4 100644 --- a/src/duckdb/src/storage/local_storage.cpp +++ b/src/duckdb/src/storage/local_storage.cpp @@ -12,24 +12,24 @@ namespace duckdb { LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &table) : context(context), table_ref(table), allocator(Allocator::Get(table.db)), deleted_rows(0), - optimistic_writer(context, table), merged_storage(false) { + optimistic_writer(context, table) { auto types = table.GetTypes(); auto data_table_info = table.GetDataTableInfo(); row_groups = optimistic_writer.CreateCollection(table, types, OptimisticWritePartialManagers::GLOBAL); auto &collection = *row_groups->collection; collection.InitializeEmpty(); - data_table_info->GetIndexes().Scan([&](Index &index) { + for (auto &index : data_table_info->GetIndexes().Indexes()) { auto constraint = index.GetConstraintType(); if (constraint == IndexConstraintType::NONE) { - return false; + continue; } if (!index.IsBound()) { - return false; + continue; } auto &bound_index = index.Cast(); if (!bound_index.SupportsDeltaIndexes()) { - return false; + continue; } // Create a delete index and a local index. @@ -38,8 +38,7 @@ LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &table) auto append_index = bound_index.CreateDeltaIndex(DeltaIndexType::LOCAL_APPEND); append_indexes.AddIndex(std::move(append_index)); - return false; - }); + } } LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &new_data_table, LocalTableStorage &parent, @@ -47,7 +46,7 @@ LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &new_data const vector &bound_columns, Expression &cast_expr) : context(context), table_ref(new_data_table), allocator(Allocator::Get(new_data_table.db)), deleted_rows(parent.deleted_rows), optimistic_collections(std::move(parent.optimistic_collections)), - optimistic_writer(new_data_table, parent.optimistic_writer), merged_storage(parent.merged_storage) { + optimistic_writer(new_data_table, parent.optimistic_writer) { // Alter the column type. auto &parent_collection = *parent.row_groups->collection; auto new_collection = @@ -63,7 +62,7 @@ LocalTableStorage::LocalTableStorage(DataTable &new_data_table, LocalTableStorag const idx_t drop_column_index) : table_ref(new_data_table), allocator(Allocator::Get(new_data_table.db)), deleted_rows(parent.deleted_rows), optimistic_collections(std::move(parent.optimistic_collections)), - optimistic_writer(new_data_table, parent.optimistic_writer), merged_storage(parent.merged_storage) { + optimistic_writer(new_data_table, parent.optimistic_writer) { // Remove the column from the previous table storage. auto &parent_collection = *parent.row_groups->collection; auto new_collection = parent_collection.RemoveColumn(drop_column_index); @@ -78,7 +77,7 @@ LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &new_dt, ColumnDefinition &new_column, ExpressionExecutor &default_executor) : table_ref(new_dt), allocator(Allocator::Get(new_dt.db)), deleted_rows(parent.deleted_rows), optimistic_collections(std::move(parent.optimistic_collections)), - optimistic_writer(new_dt, parent.optimistic_writer), merged_storage(parent.merged_storage) { + optimistic_writer(new_dt, parent.optimistic_writer) { auto &parent_collection = *parent.row_groups->collection; auto new_collection = parent_collection.AddColumn(context, new_column, default_executor); row_groups = std::move(parent.row_groups); @@ -124,13 +123,12 @@ idx_t LocalTableStorage::EstimatedSize() { // get the index size idx_t index_sizes = 0; - append_indexes.Scan([&](Index &index) { + for (auto &index : append_indexes.Indexes()) { if (!index.IsBound()) { - return false; + continue; } index_sizes += index.Cast().GetInMemorySize(); - return false; - }); + } // return the size of the appended rows and the index size return data_size + index_sizes; @@ -147,8 +145,9 @@ void LocalTableStorage::WriteNewRowGroup() { void LocalTableStorage::FlushBlocks() { auto &collection = *row_groups->collection; const idx_t row_group_size = collection.GetRowGroupSize(); - if (!merged_storage && collection.GetTotalRows() > row_group_size) { - optimistic_writer.WriteLastRowGroup(*row_groups); + if (collection.GetTotalRows() >= row_group_size) { + // write any unflushed row groups + optimistic_writer.WriteUnflushedRowGroups(*row_groups); } optimistic_writer.FinalFlush(); } @@ -188,7 +187,7 @@ ErrorData LocalTableStorage::AppendToIndexes(DuckTransaction &transaction, RowGr // index_chunk scans are created here in the mapped_column_ids ordering (see note above). ErrorData error; - source.Scan(transaction, mapped_column_ids, [&](DataChunk &index_chunk) -> bool { + for (auto &index_chunk : source.Chunks(transaction, mapped_column_ids)) { D_ASSERT(index_chunk.ColumnCount() == mapped_column_ids.size()); for (idx_t i = 0; i < mapped_column_ids.size(); i++) { auto col_id = mapped_column_ids[i].GetPrimaryIndex(); @@ -202,11 +201,10 @@ ErrorData LocalTableStorage::AppendToIndexes(DuckTransaction &transaction, RowGr error = DataTable::AppendToIndexes(index_list, delete_indexes, table_chunk, index_chunk, mapped_column_ids, start_row, index_append_mode, checkpoint_id); if (error.HasError()) { - return false; + break; } start_row += UnsafeNumericCast(index_chunk.size()); - return true; - }); + } return error; } @@ -214,11 +212,10 @@ void LocalTableStorage::AppendToTable(DuckTransaction &transaction, TableAppendS auto &table = table_ref.get(); table.InitializeAppend(transaction, append_state); auto &collection = *row_groups->collection; - collection.Scan(transaction, [&](DataChunk &table_chunk) -> bool { + for (auto &table_chunk : collection.Chunks(transaction)) { // Append to the base table. table.Append(table_chunk, append_state); - return true; - }); + } table.FinalizeAppend(transaction, append_state); } @@ -238,22 +235,21 @@ void LocalTableStorage::AppendToIndexes(DuckTransaction &transaction, TableAppen // Revert all appended row IDs. row_t current_row = append_state.row_start; // Remove the data from the indexes, if any. - collection.Scan(transaction, [&](DataChunk &chunk) -> bool { + for (auto &chunk : collection.Chunks(transaction)) { if (current_row >= append_state.current_row) { // Finished deleting all rows from the index. - return false; + break; } // Remove the chunk. try { table.RevertIndexAppend(append_state, chunk, current_row); } catch (std::exception &ex) { // LCOV_EXCL_START error = ErrorData(ex); - return false; + break; } // LCOV_EXCL_STOP current_row += UnsafeNumericCast(chunk.size()); - return true; - }); + } #ifdef DEBUG // Verify that our index memory is stable. @@ -408,6 +404,10 @@ RowGroupCollection &LocalTableStorage::GetCollection() { return *row_groups->collection; } +OptimisticWriteCollection &LocalTableStorage::GetPrimaryCollection() { + return *row_groups; +} + bool LocalStorage::NextParallelScan(ClientContext &context, DataTable &table, ParallelCollectionScanState &state, CollectionScanState &scan_state) { auto storage = table_manager.GetStorage(table); @@ -431,18 +431,17 @@ void LocalTableStorage::AppendToDeleteIndexes(Vector &row_ids, DataChunk &delete return; } - delete_indexes.Scan([&](Index &index) { + for (auto &index : delete_indexes.Indexes()) { D_ASSERT(index.IsBound()); if (!index.IsUnique()) { - return false; + continue; } IndexAppendInfo index_append_info(IndexAppendMode::IGNORE_DUPLICATES, nullptr); auto result = index.Cast().Append(delete_chunk, row_ids, index_append_info); if (result.HasError()) { throw InternalException("unexpected constraint violation on delete ART: ", result.Message()); } - return false; - }); + } } void LocalStorage::Append(LocalAppendState &state, DataChunk &table_chunk, DataTableInfo &data_table_info) { @@ -494,8 +493,8 @@ void LocalStorage::LocalMerge(DataTable &table, OptimisticWriteCollection &colle error.Throw(); } } - storage.GetCollection().MergeStorage(*collection.collection, nullptr, nullptr); - storage.merged_storage = true; + auto &target = storage.GetPrimaryCollection(); + target.MergeStorage(collection); } PhysicalIndex LocalStorage::CreateOptimisticCollection(DataTable &table, @@ -574,7 +573,6 @@ void LocalStorage::Flush(DataTable &table, LocalTableStorage &storage, optional_ TableAppendState append_state; table.AppendLock(transaction, append_state); - transaction.PushAppend(table, NumericCast(append_state.row_start), append_count); if ((append_state.row_start == 0 || storage.GetCollection().GetTotalRows() >= row_group_size) && storage.deleted_rows == 0) { // table is currently empty OR we are bulk appending: move over the storage directly @@ -583,7 +581,7 @@ void LocalStorage::Flush(DataTable &table, LocalTableStorage &storage, optional_ // Append to the indexes. storage.AppendToIndexes(transaction, append_state); // finally move over the row groups - table.MergeStorage(storage.GetCollection(), storage.append_indexes, commit_state); + table.MergeStorage(storage.GetCollection(), commit_state); } else { // check if we have written data // if we have, we cannot merge to disk after all @@ -594,6 +592,7 @@ void LocalStorage::Flush(DataTable &table, LocalTableStorage &storage, optional_ // after that is successful - append to the table storage.AppendToTable(transaction, append_state); } + transaction.PushAppend(table, NumericCast(append_state.row_start), append_count); #ifdef DEBUG // Verify that our index memory is stable. diff --git a/src/duckdb/src/storage/open_file_storage_extension.cpp b/src/duckdb/src/storage/open_file_storage_extension.cpp index 1daf5b5e6..25dbacbe9 100644 --- a/src/duckdb/src/storage/open_file_storage_extension.cpp +++ b/src/duckdb/src/storage/open_file_storage_extension.cpp @@ -71,8 +71,8 @@ unique_ptr OpenFileStorageTransactionManager(optional_ptr(db); } -unique_ptr OpenFileStorageExtension::Create() { - auto result = make_uniq(); +shared_ptr OpenFileStorageExtension::Create() { + auto result = make_shared_ptr(); result->attach = OpenFileStorageAttach; result->create_transaction_manager = OpenFileStorageTransactionManager; return result; diff --git a/src/duckdb/src/storage/optimistic_data_writer.cpp b/src/duckdb/src/storage/optimistic_data_writer.cpp index 78976ac1c..85f4da9d6 100644 --- a/src/duckdb/src/storage/optimistic_data_writer.cpp +++ b/src/duckdb/src/storage/optimistic_data_writer.cpp @@ -23,7 +23,9 @@ OptimisticDataWriter::~OptimisticDataWriter() { bool OptimisticDataWriter::PrepareWrite() { // check if we should pre-emptively write the table to disk - if (table.IsTemporary() || StorageManager::Get(table.GetAttached()).InMemory()) { + auto &attached = table.GetAttached(); + auto &storage_manager = StorageManager::Get(attached); + if (table.IsTemporary() || storage_manager.InMemory() || attached.IsReadOnly()) { return false; } // we should! write the second-to-last row group to disk @@ -63,47 +65,90 @@ void OptimisticDataWriter::WriteNewRowGroup(OptimisticWriteCollection &row_group return; } + row_groups.unflushed_row_groups.insert(row_groups.complete_row_groups); row_groups.complete_row_groups++; - auto unflushed_row_groups = row_groups.complete_row_groups - row_groups.last_flushed; - if (unflushed_row_groups >= DBConfig::GetSetting(context)) { + auto unflushed_row_groups = row_groups.unflushed_row_groups.size(); + if (unflushed_row_groups >= Settings::Get(context)) { // we have crossed our flush threshold - flush any unwritten row groups to disk vector> to_flush; vector segment_indexes; - for (idx_t i = row_groups.last_flushed; i < row_groups.complete_row_groups; i++) { - auto segment_index = NumericCast(i); + for (auto &unflushed_idx : row_groups.unflushed_row_groups) { + auto segment_index = NumericCast(unflushed_idx); to_flush.push_back(*row_groups.collection->GetRowGroup(segment_index)); segment_indexes.push_back(segment_index); } FlushToDisk(row_groups, to_flush, segment_indexes); - row_groups.last_flushed = row_groups.complete_row_groups; + row_groups.unflushed_row_groups.clear(); } } -void OptimisticDataWriter::WriteLastRowGroup(OptimisticWriteCollection &row_groups) { +void OptimisticDataWriter::WriteUnflushedRowGroups(OptimisticWriteCollection &row_groups) { // we finished writing a complete row group if (!PrepareWrite()) { return; } - // flush the last batch of row groups - vector> to_flush; - vector segment_indexes; - for (idx_t i = row_groups.last_flushed; i < row_groups.complete_row_groups; i++) { - auto segment_index = NumericCast(i); - to_flush.push_back(*row_groups.collection->GetRowGroup(segment_index)); - segment_indexes.push_back(segment_index); + // add any incomplete row groups to the set of unflushed row groups + auto total_row_groups = row_groups.collection->GetRowGroupCount(); + if (row_groups.complete_row_groups > total_row_groups) { + throw InternalException("WriteUnflushedRowGroups - complete row groups > total_row_groups"); } - // add the last (incomplete) row group - to_flush.push_back(*row_groups.collection->GetRowGroup(-1)); - segment_indexes.push_back(-1); + for (idx_t i = row_groups.complete_row_groups; i < total_row_groups; i++) { + row_groups.unflushed_row_groups.insert(i); + row_groups.complete_row_groups++; + } + if (!row_groups.unflushed_row_groups.empty()) { + // flush the last batch of row groups + vector> to_flush; + vector segment_indexes; + for (auto &unflushed_idx : row_groups.unflushed_row_groups) { + auto segment_index = NumericCast(unflushed_idx); + to_flush.push_back(*row_groups.collection->GetRowGroup(segment_index)); + segment_indexes.push_back(segment_index); + } - FlushToDisk(row_groups, to_flush, segment_indexes); + FlushToDisk(row_groups, to_flush, segment_indexes); + } for (auto &partial_manager : row_groups.partial_block_managers) { Merge(partial_manager); } + row_groups.unflushed_row_groups.clear(); row_groups.partial_block_managers.clear(); } +void OptimisticWriteCollection::MergeStorage(OptimisticWriteCollection &merge_collection) { + auto &merge_row_groups = *merge_collection.collection; + if (merge_row_groups.GetTotalRows() == 0) { + // no rows to merge - done + return; + } + // when merging the other row group is appended to the END of this row group + // that means any trailing row groups that are not yet complete are now complete (even if they are half empty) + // add them to the unflushed set + idx_t current_row_group_count = collection->GetRowGroupCount(); + if (complete_row_groups > current_row_group_count) { + throw InternalException("MergeStorage - complete row groups > total_row_groups"); + } + for (idx_t i = complete_row_groups; i < current_row_group_count; i++) { + unflushed_row_groups.insert(i); + complete_row_groups++; + } + + // now we merge the target collection into this one - take over any unflushed row groups but adjust their index + for (auto &unflushed_idx : merge_collection.unflushed_row_groups) { + unflushed_row_groups.insert(current_row_group_count + unflushed_idx); + } + complete_row_groups += merge_collection.complete_row_groups; + // finally perform the actual merge + collection->MergeStorage(merge_row_groups, nullptr, nullptr); + // check if all row groups have been flushed + // we cannot append into a row group that has been flushed + if (complete_row_groups == collection->GetRowGroupCount()) { + // if the last row group has been flushed move any new appends to a new row group + collection->SetAppendRequiresNewRowGroup(); + } +} + void OptimisticDataWriter::FlushToDisk(OptimisticWriteCollection &collection, const vector> &row_groups, const vector &segment_indexes) { diff --git a/src/duckdb/src/storage/serialization/serialize_create_info.cpp b/src/duckdb/src/storage/serialization/serialize_create_info.cpp index 4e0d48806..7e3f82192 100644 --- a/src/duckdb/src/storage/serialization/serialize_create_info.cpp +++ b/src/duckdb/src/storage/serialization/serialize_create_info.cpp @@ -168,6 +168,9 @@ void CreateTableInfo::Serialize(Serializer &serializer) const { serializer.WriteProperty(201, "columns", columns); serializer.WritePropertyWithDefault>>(202, "constraints", constraints); serializer.WritePropertyWithDefault>(203, "query", query); + serializer.WritePropertyWithDefault>>(204, "partition_keys", partition_keys); + serializer.WritePropertyWithDefault>>(205, "sort_keys", sort_keys); + serializer.WritePropertyWithDefault>>(206, "options", options); } unique_ptr CreateTableInfo::Deserialize(Deserializer &deserializer) { @@ -176,6 +179,9 @@ unique_ptr CreateTableInfo::Deserialize(Deserializer &deserializer) deserializer.ReadProperty(201, "columns", result->columns); deserializer.ReadPropertyWithDefault>>(202, "constraints", result->constraints); deserializer.ReadPropertyWithDefault>(203, "query", result->query); + deserializer.ReadPropertyWithDefault>>(204, "partition_keys", result->partition_keys); + deserializer.ReadPropertyWithDefault>>(205, "sort_keys", result->sort_keys); + deserializer.ReadPropertyWithDefault>>(206, "options", result->options); return std::move(result); } @@ -199,17 +205,27 @@ void CreateViewInfo::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(202, "types", types); serializer.WritePropertyWithDefault>(203, "query", query); serializer.WritePropertyWithDefault>(204, "names", names); - serializer.WritePropertyWithDefault>(205, "column_comments", column_comments, vector()); + if (!serializer.ShouldSerialize(7)) { + serializer.WritePropertyWithDefault>(205, "column_comments", GetColumnCommentsList()); + } + if (serializer.ShouldSerialize(7)) { + serializer.WritePropertyWithDefault>(206, "column_comments_map", column_comments_map, unordered_map()); + } } unique_ptr CreateViewInfo::Deserialize(Deserializer &deserializer) { - auto result = duckdb::unique_ptr(new CreateViewInfo()); - deserializer.ReadPropertyWithDefault(200, "view_name", result->view_name); - deserializer.ReadPropertyWithDefault>(201, "aliases", result->aliases); - deserializer.ReadPropertyWithDefault>(202, "types", result->types); - deserializer.ReadPropertyWithDefault>(203, "query", result->query); - deserializer.ReadPropertyWithDefault>(204, "names", result->names); - deserializer.ReadPropertyWithExplicitDefault>(205, "column_comments", result->column_comments, vector()); + auto view_name = deserializer.ReadPropertyWithDefault(200, "view_name"); + auto aliases = deserializer.ReadPropertyWithDefault>(201, "aliases"); + auto types = deserializer.ReadPropertyWithDefault>(202, "types"); + auto query = deserializer.ReadPropertyWithDefault>(203, "query"); + auto names = deserializer.ReadPropertyWithDefault>(204, "names"); + auto column_comments = deserializer.ReadPropertyWithDefault>(205, "column_comments"); + auto column_comments_map = deserializer.ReadPropertyWithExplicitDefault>(206, "column_comments_map", unordered_map()); + auto result = duckdb::unique_ptr(new CreateViewInfo(std::move(names), std::move(column_comments), std::move(column_comments_map))); + result->view_name = std::move(view_name); + result->aliases = std::move(aliases); + result->types = std::move(types); + result->query = std::move(query); return std::move(result); } diff --git a/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp b/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp index 4c70c25c1..5e5dfcf0e 100644 --- a/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp +++ b/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp @@ -290,6 +290,7 @@ void LogicalCTERef::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault(201, "cte_index", cte_index); serializer.WritePropertyWithDefault>(202, "chunk_types", chunk_types); serializer.WritePropertyWithDefault>(203, "bound_columns", bound_columns); + /* [Deleted] (CTEMaterialize) "materialized_cte" */ serializer.WritePropertyWithDefault(205, "is_recurring", is_recurring); } @@ -299,6 +300,7 @@ unique_ptr LogicalCTERef::Deserialize(Deserializer &deserialize auto chunk_types = deserializer.ReadPropertyWithDefault>(202, "chunk_types"); auto bound_columns = deserializer.ReadPropertyWithDefault>(203, "bound_columns"); auto result = duckdb::unique_ptr(new LogicalCTERef(table_index, cte_index, std::move(chunk_types), std::move(bound_columns))); + deserializer.ReadDeletedProperty(204, "materialized_cte"); deserializer.ReadPropertyWithDefault(205, "is_recurring", result->is_recurring); return std::move(result); } diff --git a/src/duckdb/src/storage/serialization/serialize_nodes.cpp b/src/duckdb/src/storage/serialization/serialize_nodes.cpp index 55a64a14f..06b2a72e5 100644 --- a/src/duckdb/src/storage/serialization/serialize_nodes.cpp +++ b/src/duckdb/src/storage/serialization/serialize_nodes.cpp @@ -5,8 +5,6 @@ #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/common/types.hpp" -#include "duckdb/common/extra_type_info.hpp" #include "duckdb/parser/common_table_expression_info.hpp" #include "duckdb/parser/query_node.hpp" #include "duckdb/parser/result_modifier.hpp" @@ -36,6 +34,8 @@ #include "duckdb/common/column_index.hpp" #include "duckdb/common/table_column.hpp" #include "duckdb/common/extra_operator_info.hpp" +#include "duckdb/storage/table/row_group_reorderer.hpp" +#include "duckdb/storage/storage_index.hpp" namespace duckdb { @@ -220,6 +220,8 @@ void ColumnIndex::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(2, "child_indexes", child_indexes); serializer.WritePropertyWithDefault(3, "index_type", index_type, ColumnIndexType::FULL_READ); serializer.WritePropertyWithDefault(4, "type", type, LogicalType::INVALID); + serializer.WritePropertyWithDefault(5, "field", field, ""); + serializer.WritePropertyWithDefault(6, "has_index", has_index, true); } ColumnIndex ColumnIndex::Deserialize(Deserializer &deserializer) { @@ -228,6 +230,8 @@ ColumnIndex ColumnIndex::Deserialize(Deserializer &deserializer) { deserializer.ReadPropertyWithDefault>(2, "child_indexes", result.child_indexes); deserializer.ReadPropertyWithExplicitDefault(3, "index_type", result.index_type, ColumnIndexType::FULL_READ); deserializer.ReadPropertyWithExplicitDefault(4, "type", result.type, LogicalType::INVALID); + deserializer.ReadPropertyWithExplicitDefault(5, "field", result.field, ""); + deserializer.ReadPropertyWithExplicitDefault(6, "has_index", result.has_index, true); return result; } @@ -349,18 +353,6 @@ JoinCondition JoinCondition::Deserialize(Deserializer &deserializer) { return result; } -void LogicalType::Serialize(Serializer &serializer) const { - serializer.WriteProperty(100, "id", id_); - serializer.WritePropertyWithDefault>(101, "type_info", type_info_); -} - -LogicalType LogicalType::Deserialize(Deserializer &deserializer) { - auto id = deserializer.ReadProperty(100, "id"); - auto type_info = deserializer.ReadPropertyWithDefault>(101, "type_info"); - LogicalType result(id, std::move(type_info)); - return result; -} - void MultiFileOptions::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault(100, "filename", filename); serializer.WritePropertyWithDefault(101, "hive_partitioning", hive_partitioning); @@ -425,20 +417,6 @@ PivotColumn PivotColumn::Deserialize(Deserializer &deserializer) { return result; } -void PivotColumnEntry::Serialize(Serializer &serializer) const { - serializer.WritePropertyWithDefault>(100, "values", values); - serializer.WritePropertyWithDefault>(101, "star_expr", expr); - serializer.WritePropertyWithDefault(102, "alias", alias); -} - -PivotColumnEntry PivotColumnEntry::Deserialize(Deserializer &deserializer) { - PivotColumnEntry result; - deserializer.ReadPropertyWithDefault>(100, "values", result.values); - deserializer.ReadPropertyWithDefault>(101, "star_expr", result.expr); - deserializer.ReadPropertyWithDefault(102, "alias", result.alias); - return result; -} - void QualifiedColumnName::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault(100, "catalog", catalog); serializer.WritePropertyWithDefault(101, "schema", schema); @@ -481,6 +459,26 @@ unique_ptr ReservoirSamplePercentage::Deserialize(Deserializer & return std::move(result); } +void RowGroupOrderOptions::Serialize(Serializer &serializer) const { + serializer.WriteProperty(100, "column_idx", column_idx); + serializer.WriteProperty(101, "order_by", order_by); + serializer.WriteProperty(102, "order_type", order_type); + serializer.WriteProperty(103, "column_type", column_type); + serializer.WriteProperty(104, "row_limit", row_limit); + serializer.WritePropertyWithDefault(105, "row_group_offset", row_group_offset); +} + +unique_ptr RowGroupOrderOptions::Deserialize(Deserializer &deserializer) { + auto column_idx = deserializer.ReadProperty(100, "column_idx"); + auto order_by = deserializer.ReadProperty(101, "order_by"); + auto order_type = deserializer.ReadProperty(102, "order_type"); + auto column_type = deserializer.ReadProperty(103, "column_type"); + auto row_limit = deserializer.ReadProperty(104, "row_limit"); + auto row_group_offset = deserializer.ReadPropertyWithDefault(105, "row_group_offset"); + auto result = duckdb::unique_ptr(new RowGroupOrderOptions(column_idx, order_by, order_type, column_type, row_limit, row_group_offset)); + return result; +} + void SampleOptions::Serialize(Serializer &serializer) const { serializer.WriteProperty(100, "sample_size", sample_size); serializer.WritePropertyWithDefault(101, "is_percentage", is_percentage); @@ -659,6 +657,26 @@ SerializedReadCSVData SerializedReadCSVData::Deserialize(Deserializer &deseriali return result; } +void StorageIndex::Serialize(Serializer &serializer) const { + serializer.WritePropertyWithDefault(100, "has_index", has_index); + serializer.WritePropertyWithDefault(101, "index", index); + serializer.WritePropertyWithDefault(102, "field", field); + serializer.WriteProperty(103, "type", type); + serializer.WriteProperty(104, "index_type", index_type); + serializer.WritePropertyWithDefault>(105, "child_indexes", child_indexes); +} + +StorageIndex StorageIndex::Deserialize(Deserializer &deserializer) { + StorageIndex result; + deserializer.ReadPropertyWithDefault(100, "has_index", result.has_index); + deserializer.ReadPropertyWithDefault(101, "index", result.index); + deserializer.ReadPropertyWithDefault(102, "field", result.field); + deserializer.ReadProperty(103, "type", result.type); + deserializer.ReadProperty(104, "index_type", result.index_type); + deserializer.ReadPropertyWithDefault>(105, "child_indexes", result.child_indexes); + return result; +} + void StrpTimeFormat::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault(100, "format_specifier", format_specifier); } diff --git a/src/duckdb/src/storage/serialization/serialize_parse_info.cpp b/src/duckdb/src/storage/serialization/serialize_parse_info.cpp index a5616e0e6..e5ffc2c45 100644 --- a/src/duckdb/src/storage/serialization/serialize_parse_info.cpp +++ b/src/duckdb/src/storage/serialization/serialize_parse_info.cpp @@ -164,6 +164,9 @@ unique_ptr AlterTableInfo::Deserialize(Deserializer &deserializer) { case AlterTableType::RENAME_TABLE: result = RenameTableInfo::Deserialize(deserializer); break; + case AlterTableType::RESET_TABLE_OPTIONS: + result = ResetTableOptionsInfo::Deserialize(deserializer); + break; case AlterTableType::SET_DEFAULT: result = SetDefaultInfo::Deserialize(deserializer); break; @@ -176,6 +179,9 @@ unique_ptr AlterTableInfo::Deserialize(Deserializer &deserializer) { case AlterTableType::SET_SORTED_BY: result = SetSortedByInfo::Deserialize(deserializer); break; + case AlterTableType::SET_TABLE_OPTIONS: + result = SetTableOptionsInfo::Deserialize(deserializer); + break; default: throw SerializationException("Unsupported type for deserialization of AlterTableInfo!"); } @@ -550,6 +556,17 @@ unique_ptr RenameViewInfo::Deserialize(Deserializer &deserializer return std::move(result); } +void ResetTableOptionsInfo::Serialize(Serializer &serializer) const { + AlterTableInfo::Serialize(serializer); + serializer.WriteProperty(400, "table_options", table_options); +} + +unique_ptr ResetTableOptionsInfo::Deserialize(Deserializer &deserializer) { + auto result = duckdb::unique_ptr(new ResetTableOptionsInfo()); + deserializer.ReadProperty(400, "table_options", result->table_options); + return std::move(result); +} + void SetColumnCommentInfo::Serialize(Serializer &serializer) const { AlterInfo::Serialize(serializer); serializer.WriteProperty(300, "catalog_entry_type", catalog_entry_type); @@ -624,6 +641,17 @@ unique_ptr SetSortedByInfo::Deserialize(Deserializer &deserializ return std::move(result); } +void SetTableOptionsInfo::Serialize(Serializer &serializer) const { + AlterTableInfo::Serialize(serializer); + serializer.WritePropertyWithDefault>>(400, "table_options", table_options); +} + +unique_ptr SetTableOptionsInfo::Deserialize(Deserializer &deserializer) { + auto result = duckdb::unique_ptr(new SetTableOptionsInfo()); + deserializer.ReadPropertyWithDefault>>(400, "table_options", result->table_options); + return std::move(result); +} + void TransactionInfo::Serialize(Serializer &serializer) const { ParseInfo::Serialize(serializer); serializer.WriteProperty(200, "type", type); diff --git a/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp b/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp index 54dfd646e..dc54bc327 100644 --- a/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp +++ b/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp @@ -75,6 +75,9 @@ unique_ptr ParsedExpression::Deserialize(Deserializer &deseria case ExpressionClass::SUBQUERY: result = SubqueryExpression::Deserialize(deserializer); break; + case ExpressionClass::TYPE: + result = TypeExpression::Deserialize(deserializer); + break; case ExpressionClass::WINDOW: result = WindowExpression::Deserialize(deserializer); break; @@ -331,6 +334,23 @@ unique_ptr SubqueryExpression::Deserialize(Deserializer &deser return std::move(result); } +void TypeExpression::Serialize(Serializer &serializer) const { + ParsedExpression::Serialize(serializer); + serializer.WritePropertyWithDefault(200, "catalog", catalog); + serializer.WritePropertyWithDefault(201, "schema", schema); + serializer.WritePropertyWithDefault(202, "type_name", type_name); + serializer.WritePropertyWithDefault>>(203, "children", children); +} + +unique_ptr TypeExpression::Deserialize(Deserializer &deserializer) { + auto result = duckdb::unique_ptr(new TypeExpression()); + deserializer.ReadPropertyWithDefault(200, "catalog", result->catalog); + deserializer.ReadPropertyWithDefault(201, "schema", result->schema); + deserializer.ReadPropertyWithDefault(202, "type_name", result->type_name); + deserializer.ReadPropertyWithDefault>>(203, "children", result->children); + return std::move(result); +} + void WindowExpression::Serialize(Serializer &serializer) const { ParsedExpression::Serialize(serializer); serializer.WritePropertyWithDefault(200, "function_name", function_name); diff --git a/src/duckdb/src/storage/serialization/serialize_types.cpp b/src/duckdb/src/storage/serialization/serialize_types.cpp index 8e77ef866..b7dec4ab3 100644 --- a/src/duckdb/src/storage/serialization/serialize_types.cpp +++ b/src/duckdb/src/storage/serialization/serialize_types.cpp @@ -62,8 +62,8 @@ shared_ptr ExtraTypeInfo::Deserialize(Deserializer &deserializer) case ExtraTypeInfoType::TEMPLATE_TYPE_INFO: result = TemplateTypeInfo::Deserialize(deserializer); break; - case ExtraTypeInfoType::USER_TYPE_INFO: - result = UserTypeInfo::Deserialize(deserializer); + case ExtraTypeInfoType::UNBOUND_TYPE_INFO: + result = UnboundTypeInfo::Deserialize(deserializer); break; default: throw SerializationException("Unsupported type for deserialization of ExtraTypeInfo!"); @@ -217,21 +217,4 @@ shared_ptr TemplateTypeInfo::Deserialize(Deserializer &deserializ return std::move(result); } -void UserTypeInfo::Serialize(Serializer &serializer) const { - ExtraTypeInfo::Serialize(serializer); - serializer.WritePropertyWithDefault(200, "user_type_name", user_type_name); - serializer.WritePropertyWithDefault(201, "catalog", catalog, string()); - serializer.WritePropertyWithDefault(202, "schema", schema, string()); - serializer.WritePropertyWithDefault>(203, "user_type_modifiers", user_type_modifiers); -} - -shared_ptr UserTypeInfo::Deserialize(Deserializer &deserializer) { - auto result = duckdb::shared_ptr(new UserTypeInfo()); - deserializer.ReadPropertyWithDefault(200, "user_type_name", result->user_type_name); - deserializer.ReadPropertyWithExplicitDefault(201, "catalog", result->catalog, string()); - deserializer.ReadPropertyWithExplicitDefault(202, "schema", result->schema, string()); - deserializer.ReadPropertyWithDefault>(203, "user_type_modifiers", result->user_type_modifiers); - return std::move(result); -} - } // namespace duckdb diff --git a/src/duckdb/src/storage/single_file_block_manager.cpp b/src/duckdb/src/storage/single_file_block_manager.cpp index aeba13f51..c43fc5967 100644 --- a/src/duckdb/src/storage/single_file_block_manager.cpp +++ b/src/duckdb/src/storage/single_file_block_manager.cpp @@ -8,6 +8,8 @@ #include "duckdb/common/encryption_state.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/serializer/memory_stream.hpp" +#include "duckdb/common/enums/checkpoint_abort.hpp" +#include "duckdb/common/enums/storage_block_prefetch.hpp" #include "duckdb/main/attached_database.hpp" #include "duckdb/main/config.hpp" #include "duckdb/main/database.hpp" @@ -26,6 +28,7 @@ namespace duckdb { const char MainHeader::MAGIC_BYTES[] = "DUCK"; const char MainHeader::CANARY[] = "DUCKKEY"; +static constexpr idx_t ENCRYPTION_METADATA_LEN = 8; void SerializeVersionNumber(WriteStream &ser, const string &version_str) { data_t version[MainHeader::MAX_VERSION_SIZE]; @@ -53,6 +56,32 @@ void SerializeEncryptionMetadata(WriteStream &ser, data_ptr_t metadata_p, const ser.WriteData(metadata, MainHeader::ENCRYPTION_METADATA_LEN); } +void SerializeIV(WriteStream &ser, data_ptr_t metadata_p, const bool encrypted) { + // Used for Canary encryption + // Zero-initialize. + data_t iv[MainHeader::AES_NONCE_LEN]; + memset(iv, 0, MainHeader::AES_NONCE_LEN); + + // Write metadata, if encrypted. + if (encrypted) { + memcpy(iv, metadata_p, MainHeader::AES_NONCE_LEN); + } + ser.WriteData(iv, MainHeader::AES_NONCE_LEN); +} + +void SerializeTag(WriteStream &ser, data_ptr_t metadata_p, const bool encrypted) { + // Used for Canary encryption + // Zero-initialize. + data_t tag[MainHeader::AES_TAG_LEN]; + memset(tag, 0, MainHeader::AES_TAG_LEN); + + // Write metadata, if encrypted. + if (encrypted) { + memcpy(tag, metadata_p, MainHeader::AES_TAG_LEN); + } + ser.WriteData(tag, MainHeader::AES_TAG_LEN); +} + void DeserializeVersionNumber(ReadStream &stream, data_t *dest) { memset(dest, 0, MainHeader::MAX_VERSION_SIZE); stream.ReadData(dest, MainHeader::MAX_VERSION_SIZE); @@ -71,39 +100,73 @@ void GenerateDBIdentifier(uint8_t *db_identifier) { void EncryptCanary(MainHeader &main_header, const shared_ptr &encryption_state, const_data_ptr_t derived_key) { - uint8_t canary_buffer[MainHeader::CANARY_BYTE_SIZE]; - - // we zero-out the iv and the (not yet) encrypted canary - uint8_t iv[MainHeader::AES_IV_LEN]; - memset(iv, 0, MainHeader::AES_IV_LEN); - memset(canary_buffer, 0, MainHeader::CANARY_BYTE_SIZE); - - encryption_state->InitializeEncryption(iv, MainHeader::AES_IV_LEN, derived_key, - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); - encryption_state->Process(reinterpret_cast(MainHeader::CANARY), MainHeader::CANARY_BYTE_SIZE, - canary_buffer, MainHeader::CANARY_BYTE_SIZE); + EncryptionCanary canary; + EncryptionNonce nonce(EncryptionTypes::CipherType::GCM, encryption_state->metadata->GetVersion()); + memset(nonce.data(), 0, nonce.size()); + EncryptionTag tag; + + switch (encryption_state->metadata->GetVersion()) { + case EncryptionTypes::V0_0: + D_ASSERT(nonce.total_size() == MainHeader::AES_NONCE_LEN_DEPRECATED); + encryption_state->InitializeEncryption(nonce, derived_key); + encryption_state->Process(reinterpret_cast(MainHeader::CANARY), canary.size(), canary.data(), + canary.size()); + break; + case EncryptionTypes::V0_1: + // for GCM, total nonce size should be always equal to 12 bytes + D_ASSERT(nonce.total_size() == MainHeader::AES_NONCE_LEN); + encryption_state->GenerateRandomData(nonce.data(), nonce.size()); + main_header.SetCanaryIV(nonce.data()); + encryption_state->InitializeEncryption(nonce, derived_key); + encryption_state->Process(reinterpret_cast(MainHeader::CANARY), canary.size(), canary.data(), + canary.size()); + encryption_state->Finalize(canary.data(), canary.size(), tag.data(), MainHeader::AES_TAG_LEN); + main_header.SetCanaryTag(tag.data()); + break; + default: + throw InvalidInputException("No valid encryption version found!"); + } - main_header.SetEncryptedCanary(canary_buffer); + main_header.SetEncryptedCanary(canary.data()); } bool DecryptCanary(MainHeader &main_header, const shared_ptr &encryption_state, data_ptr_t derived_key) { - // just zero-out the iv - uint8_t iv[MainHeader::AES_IV_LEN]; - memset(iv, 0, MainHeader::AES_IV_LEN); - - //! allocate a buffer for the decrypted canary - data_t decrypted_canary[MainHeader::CANARY_BYTE_SIZE]; - memset(decrypted_canary, 0, MainHeader::CANARY_BYTE_SIZE); - - //! Decrypt the canary - encryption_state->InitializeDecryption(iv, MainHeader::AES_IV_LEN, derived_key, - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); - encryption_state->Process(main_header.GetEncryptedCanary(), MainHeader::CANARY_BYTE_SIZE, decrypted_canary, - MainHeader::CANARY_BYTE_SIZE); - - //! compare if the decrypted canary is correct - if (memcmp(decrypted_canary, MainHeader::CANARY, MainHeader::CANARY_BYTE_SIZE) != 0) { + auto encryption_version = encryption_state->metadata->GetVersion(); + EncryptionNonce nonce(EncryptionTypes::CipherType::GCM, encryption_version); + EncryptionTag tag; + EncryptionCanary decrypted_canary; + + switch (encryption_version) { + case EncryptionTypes::V0_0: + D_ASSERT(nonce.total_size() == MainHeader::AES_NONCE_LEN_DEPRECATED); + //! Decrypt the canary, Nonce is zeroed out + encryption_state->InitializeDecryption(nonce, derived_key); + encryption_state->Process(main_header.GetEncryptedCanary(), decrypted_canary.size(), decrypted_canary.data(), + decrypted_canary.size()); + break; + case EncryptionTypes::V0_1: + D_ASSERT(nonce.total_size() == MainHeader::AES_NONCE_LEN); + // get the IV and the Tag + memcpy(nonce.data(), main_header.GetIV(), nonce.total_size()); + memcpy(tag.data(), main_header.GetTag(), tag.size()); + + //! Decrypt the canary + encryption_state->InitializeDecryption(nonce, derived_key); + encryption_state->Process(main_header.GetEncryptedCanary(), decrypted_canary.size(), decrypted_canary.data(), + decrypted_canary.size()); + try { + encryption_state->Finalize(decrypted_canary.data(), decrypted_canary.size(), tag.data(), tag.size()); + } catch (const std::exception &e) { + throw InvalidInputException("Wrong encryption key used to open the database file"); + } + break; + default: + throw InvalidInputException("No valid encryption version found!"); + } + + //! compare to check whether the decrypted canary is correct + if (memcmp(decrypted_canary.data(), MainHeader::CANARY, MainHeader::CANARY_BYTE_SIZE) != 0) { return false; } @@ -125,6 +188,8 @@ void MainHeader::Write(WriteStream &ser) { SerializeEncryptionMetadata(ser, encryption_metadata, encryption_enabled); SerializeDBIdentifier(ser, db_identifier); SerializeEncryptionMetadata(ser, encrypted_canary, encryption_enabled); + SerializeIV(ser, canary_iv, encryption_enabled); + SerializeTag(ser, canary_tag, encryption_enabled); } void MainHeader::CheckMagicBytes(QueryContext context, FileHandle &handle) { @@ -175,7 +240,6 @@ MainHeader MainHeader::Read(ReadStream &source) { for (idx_t i = 0; i < FLAG_COUNT; i++) { header.flags[i] = source.Read(); } - DeserializeVersionNumber(source, header.library_git_desc); DeserializeVersionNumber(source, header.library_git_hash); @@ -183,6 +247,8 @@ MainHeader MainHeader::Read(ReadStream &source) { DeserializeEncryptionData(source, header.encryption_metadata, MainHeader::ENCRYPTION_METADATA_LEN); DeserializeEncryptionData(source, header.db_identifier, MainHeader::DB_IDENTIFIER_LEN); DeserializeEncryptionData(source, header.encrypted_canary, MainHeader::CANARY_BYTE_SIZE); + DeserializeEncryptionData(source, header.canary_iv, MainHeader::AES_NONCE_LEN); + DeserializeEncryptionData(source, header.canary_tag, MainHeader::AES_TAG_LEN); return header; } @@ -301,8 +367,22 @@ MainHeader ConstructMainHeader(idx_t version_number) { void SingleFileBlockManager::StoreEncryptedCanary(AttachedDatabase &db, MainHeader &main_header, const string &key_id) { const_data_ptr_t key = EncryptionEngine::GetKeyFromCache(db.GetDatabase(), key_id); // Encrypt canary with the derived key - auto encryption_state = db.GetDatabase().GetEncryptionUtil()->CreateEncryptionState( - main_header.GetEncryptionCipher(), MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + shared_ptr encryption_state; + auto encryption_version = static_cast(main_header.GetEncryptionVersion()); + if (encryption_version > EncryptionTypes::V0_0 && encryption_version != EncryptionTypes::NONE) { + // From Encryption Version 1+, always encrypt canary with GCM + auto metadata = make_uniq( + EncryptionTypes::GCM, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, encryption_version); + encryption_state = + db.GetDatabase().GetEncryptionUtil(db.IsReadOnly())->CreateEncryptionState(std::move(metadata)); + } else { + auto metadata = make_uniq( + static_cast(main_header.GetEncryptionCipher()), + MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, encryption_version); + encryption_state = + db.GetDatabase().GetEncryptionUtil(db.IsReadOnly())->CreateEncryptionState(std::move(metadata)); + } + EncryptCanary(main_header, encryption_state, key); } @@ -310,26 +390,26 @@ void SingleFileBlockManager::StoreDBIdentifier(MainHeader &main_header, data_ptr main_header.SetDBIdentifier(db_identifier); } +template +void SingleFileBlockManager::WriteEncryptionData(MemoryStream &stream, const T &val) { + stream.WriteData(reinterpret_cast(&val), sizeof(val)); +} + void SingleFileBlockManager::StoreEncryptionMetadata(MainHeader &main_header) const { // The first byte is the key derivation function (kdf). // The second byte is for the usage of AAD. // The third byte is for the cipher. // The subsequent byte is empty. // The last 4 bytes are the key length. + auto metadata_stream = make_uniq(ENCRYPTION_METADATA_LEN); - uint8_t metadata[MainHeader::ENCRYPTION_METADATA_LEN]; - memset(metadata, 0, MainHeader::ENCRYPTION_METADATA_LEN); - data_ptr_t offset = metadata; - - Store(options.encryption_options.kdf, offset); - offset++; - Store(options.encryption_options.additional_authenticated_data, offset); - offset++; - Store(db.GetStorageManager().GetCipher(), offset); - offset += 2; - Store(options.encryption_options.key_length, offset); + WriteEncryptionData(*metadata_stream, options.encryption_options.kdf); + WriteEncryptionData(*metadata_stream, options.encryption_options.additional_authenticated_data); + WriteEncryptionData(*metadata_stream, db.GetStorageManager().GetCipher()); + WriteEncryptionData(*metadata_stream, options.encryption_options.encryption_version); + WriteEncryptionData(*metadata_stream, options.encryption_options.key_length); - main_header.SetEncryptionMetadata(metadata); + main_header.SetEncryptionMetadata(metadata_stream->GetData()); } void SingleFileBlockManager::CheckAndAddEncryptionKey(MainHeader &main_header, string &user_key) { @@ -343,10 +423,24 @@ void SingleFileBlockManager::CheckAndAddEncryptionKey(MainHeader &main_header, s data_t derived_key[MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH]; EncryptionKeyManager::DeriveKey(user_key, db_identifier, derived_key); - auto encryption_state = db.GetDatabase().GetEncryptionUtil()->CreateEncryptionState( - main_header.GetEncryptionCipher(), MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + shared_ptr encryption_state; + auto encryption_version = static_cast(main_header.GetEncryptionVersion()); + if (encryption_version > EncryptionTypes::V0_0 && encryption_version != EncryptionTypes::NONE) { + // From Encryption Version 1+, always encrypt canary with GCM + auto metadata = make_uniq( + EncryptionTypes::GCM, MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, encryption_version); + encryption_state = + db.GetDatabase().GetEncryptionUtil(db.IsReadOnly())->CreateEncryptionState(std::move(metadata)); + } else { + auto metadata = make_uniq( + static_cast(main_header.GetEncryptionCipher()), + MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, encryption_version); + encryption_state = + db.GetDatabase().GetEncryptionUtil(db.IsReadOnly())->CreateEncryptionState(std::move(metadata)); + } + if (!DecryptCanary(main_header, encryption_state, derived_key)) { - throw IOException("Wrong encryption key used to open the database file"); + throw InvalidInputException("Wrong encryption key used to open the database file"); } options.encryption_options.derived_key_id = EncryptionEngine::AddKeyToCache(db.GetDatabase(), derived_key); @@ -367,11 +461,8 @@ void SingleFileBlockManager::CreateNewDatabase(QueryContext context) { auto encryption_enabled = options.encryption_options.encryption_enabled; if (encryption_enabled) { - if (!db.GetDatabase().GetEncryptionUtil()->SupportsEncryption() && !options.read_only) { - throw InvalidConfigurationException( - "The database was opened with encryption enabled, but DuckDB currently has a read-only crypto module " - "loaded. Please re-open using READONLY, or ensure httpfs is loaded using `LOAD httpfs`."); - } + // Check if we can read/write the encrypted database + db.GetDatabase().GetEncryptionUtil(options.read_only); } // open the RDBMS handle @@ -409,6 +500,12 @@ void SingleFileBlockManager::CreateNewDatabase(QueryContext context) { // Set the encrypted DB bit to 1. main_header.SetEncrypted(); + if (options.encryption_options.encryption_version == EncryptionTypes::NONE) { + throw InvalidConfigurationException("No Encryption type set"); + } + + main_header.SetEncryptionVersion(options.encryption_options.encryption_version); + // The derived key is wiped in AddKeyToCache. options.encryption_options.derived_key_id = EncryptionEngine::AddKeyToCache(db.GetDatabase(), derived_key); auto &catalog = db.GetCatalog().Cast(); @@ -496,16 +593,15 @@ void SingleFileBlockManager::LoadExistingDatabase(QueryContext context) { } if (main_header.IsEncrypted()) { + auto &storage_manager = db.GetStorageManager(); if (options.encryption_options.encryption_enabled) { //! Encryption is set + D_ASSERT(db.GetStorageManager().IsEncrypted()); + options.encryption_options.encryption_version = + static_cast(main_header.GetEncryptionVersion()); - //! Check if our encryption module can write, if not, we should throw here - if (!db.GetDatabase().GetEncryptionUtil()->SupportsEncryption() && !options.read_only) { - throw InvalidConfigurationException( - "The database is encrypted, but DuckDB currently has a read-only crypto module loaded. Either " - "re-open the database using `ATTACH '..' (READONLY)`, or ensure httpfs is loaded using `LOAD " - "httpfs`."); - } + //! Check if our encryption module can write, if not, we throw + db.GetDatabase().GetEncryptionUtil(options.read_only); //! Check if the given key upon attach is correct // Derive the encryption key and add it to cache @@ -518,8 +614,8 @@ void SingleFileBlockManager::LoadExistingDatabase(QueryContext context) { } // if a cipher was provided, check if it is the same as in the config - auto stored_cipher = main_header.GetEncryptionCipher(); - auto config_cipher = db.GetStorageManager().GetCipher(); + auto stored_cipher = static_cast(main_header.GetEncryptionCipher()); + auto config_cipher = storage_manager.GetCipher(); if (config_cipher != EncryptionTypes::INVALID && config_cipher != stored_cipher) { throw CatalogException("Cannot open encrypted database \"%s\" with a different cipher (%s) than the one " "used to create it (%s)", @@ -527,7 +623,8 @@ void SingleFileBlockManager::LoadExistingDatabase(QueryContext context) { EncryptionTypes::CipherToString(stored_cipher)); } - // This avoids the cipher from being downgrades by an attacker FIXME: we likely want to have a propervalidation + // This avoids the cipher from being downgrades by an attacker + // FIXME: we likely want to have a proper validation // of the cipher used instead of this trick to avoid downgrades if (stored_cipher != EncryptionTypes::GCM) { if (config_cipher == EncryptionTypes::INVALID) { @@ -540,7 +637,10 @@ void SingleFileBlockManager::LoadExistingDatabase(QueryContext context) { } // this is ugly, but the storage manager does not know the cipher type before - db.GetStorageManager().SetCipher(stored_cipher); + storage_manager.SetCipher(stored_cipher); + // encryption version can be overridden by the serialized encryption version + storage_manager.SetEncryptionVersion( + static_cast(main_header.GetEncryptionVersion())); } options.version_number = main_header.version_number; @@ -727,26 +827,24 @@ bool SingleFileBlockManager::IsRootBlock(MetaBlockPointer root) { } block_id_t SingleFileBlockManager::GetFreeBlockIdInternal(FreeBlockType type) { - block_id_t block; - { - lock_guard lock(block_lock); - if (!free_list.empty()) { - // The free list is not empty, so we take its first element. - block = *free_list.begin(); - // erase the entry from the free list again - free_list.erase(free_list.begin()); - } else { - block = max_block++; - } - // add the entry to the list of newly used blocks - if (type == FreeBlockType::NEWLY_USED_BLOCK) { - newly_used_blocks.insert(block); - } + lock_guard lock(single_file_block_lock); + block_id_t block_id; + if (!free_list.empty()) { + // The free list is not empty, so we take its first element. + block_id = *free_list.begin(); + // erase the entry from the free list again + free_list.erase(free_list.begin()); + } else { + block_id = max_block++; + } + // add the entry to the list of newly used blocks + if (type == FreeBlockType::NEWLY_USED_BLOCK) { + newly_used_blocks.insert(block_id); } - if (BlockIsRegistered(block)) { - throw InternalException("Free block %d is already registered", block); + if (BlockIsRegistered(block_id)) { + throw InternalException("Free block %d is already registered", block_id); } - return block; + return block_id; } block_id_t SingleFileBlockManager::GetFreeBlockId() { @@ -758,7 +856,7 @@ block_id_t SingleFileBlockManager::GetFreeBlockIdForCheckpoint() { } block_id_t SingleFileBlockManager::PeekFreeBlockId() { - lock_guard lock(block_lock); + lock_guard lock(single_file_block_lock); if (!free_list.empty()) { return *free_list.begin(); } else { @@ -767,13 +865,13 @@ block_id_t SingleFileBlockManager::PeekFreeBlockId() { } void SingleFileBlockManager::MarkBlockACheckpointed(block_id_t block_id) { - lock_guard lock(block_lock); + lock_guard lock(single_file_block_lock); D_ASSERT(block_id >= 0); newly_used_blocks.erase(block_id); } void SingleFileBlockManager::MarkBlockAsUsed(block_id_t block_id) { - lock_guard lock(block_lock); + lock_guard lock(single_file_block_lock); D_ASSERT(block_id >= 0); if (max_block <= block_id) { // the block is past the current max_block @@ -795,7 +893,7 @@ void SingleFileBlockManager::MarkBlockAsUsed(block_id_t block_id) { } void SingleFileBlockManager::MarkBlockAsModified(block_id_t block_id) { - lock_guard lock(block_lock); + unique_lock lock(single_file_block_lock); D_ASSERT(block_id >= 0); D_ASSERT(block_id < max_block); @@ -823,11 +921,7 @@ void SingleFileBlockManager::MarkBlockAsModified(block_id_t block_id) { // this block was newly used - and now we are labeling it as no longer being required // we can directly add it back to the free list newly_used_blocks.erase(block_id); - if (BlockIsRegistered(block_id)) { - free_blocks_in_use.insert(block_id); - } else { - free_list.insert(block_id); - } + AddFreeBlock(lock, block_id); } else { // this block was used in storage, we cannot directly re-use it // add it to the modified blocks indicating it will be re-usable after the next checkpoint @@ -849,7 +943,7 @@ void SingleFileBlockManager::IncreaseBlockReferenceCountInternal(block_id_t bloc void SingleFileBlockManager::VerifyBlocks(const unordered_map &block_usage_count) { // probably don't need this? - lock_guard lock(block_lock); + lock_guard lock(single_file_block_lock); // all blocks should be accounted for - either in the block_usage_count, or in the free list set referenced_blocks; for (auto &block : block_usage_count) { @@ -938,7 +1032,7 @@ void SingleFileBlockManager::VerifyBlocks(const unordered_map } void SingleFileBlockManager::IncreaseBlockReferenceCount(block_id_t block_id) { - lock_guard lock(block_lock); + lock_guard lock(single_file_block_lock); IncreaseBlockReferenceCountInternal(block_id); } @@ -947,12 +1041,12 @@ idx_t SingleFileBlockManager::GetMetaBlock() { } idx_t SingleFileBlockManager::TotalBlocks() { - lock_guard lock(block_lock); + lock_guard lock(single_file_block_lock); return NumericCast(max_block); } idx_t SingleFileBlockManager::FreeBlocks() { - lock_guard lock(block_lock); + lock_guard lock(single_file_block_lock); return free_list.size(); } @@ -961,7 +1055,7 @@ bool SingleFileBlockManager::IsRemote() { } bool SingleFileBlockManager::Prefetch() { - switch (DBConfig::GetSetting(db.GetDatabase())) { + switch (Settings::Get(db.GetDatabase())) { case StorageBlockPrefetch::NEVER: return false; case StorageBlockPrefetch::DEBUG_FORCE_ALWAYS: @@ -1058,7 +1152,7 @@ void SingleFileBlockManager::Write(QueryContext context, FileBuffer &buffer, blo void SingleFileBlockManager::Truncate() { BlockManager::Truncate(); - lock_guard guard(block_lock); + lock_guard guard(single_file_block_lock); idx_t blocks_to_truncate = 0; // reverse iterate over the free-list for (auto entry = free_list.rbegin(); entry != free_list.rend(); entry++) { @@ -1087,7 +1181,9 @@ vector SingleFileBlockManager::GetFreeListBlocks() { auto block_size = metadata_manager.GetMetadataBlockSize() - sizeof(idx_t); idx_t allocated_size = 0; while (true) { - auto free_list_size = sizeof(uint64_t) + sizeof(block_id_t) * (free_list.size() + modified_blocks.size()); + auto free_list_count = + free_list.size() + modified_blocks.size() + free_blocks_in_use.size() + newly_used_blocks.size(); + auto free_list_size = sizeof(uint64_t) + sizeof(block_id_t) * free_list_count; auto multi_use_blocks_size = sizeof(uint64_t) + (sizeof(block_id_t) + sizeof(uint32_t)) * multi_use_blocks.size(); auto metadata_blocks = @@ -1116,13 +1212,34 @@ class FreeListBlockWriter : public MetadataWriter { protected: MetadataHandle NextHandle() override { if (index >= free_list_blocks.size()) { - throw InternalException( - "Free List Block Writer ran out of blocks, this means not enough blocks were allocated up front"); + throw InternalException("Free List Block Writer ran out of blocks, this means not enough blocks were " + "allocated up front (%d total allocated)", + free_list_blocks.size()); } return std::move(free_list_blocks[index++]); } }; +bool SingleFileBlockManager::AddFreeBlock(unique_lock &lock, block_id_t block_id) { + if (!lock.owns_lock()) { + throw InternalException("AddFreeBlock must be called while holding the lock"); + } + shared_ptr block = TryGetBlock(block_id); + if (!block) { + // the block does not exist + // regular free block + free_list.insert(block_id); + return true; + } + // the block exists - add to blocks in use + free_blocks_in_use.insert(block_id); + + // release the lock while destroying the block since the block destructor can call UnregisterBlock + lock.unlock(); + block.reset(); + lock.lock(); + return false; +} void SingleFileBlockManager::WriteHeader(QueryContext context, DatabaseHeader header) { auto free_list_blocks = GetFreeListBlocks(); @@ -1131,7 +1248,7 @@ void SingleFileBlockManager::WriteHeader(QueryContext context, DatabaseHeader he // add all modified blocks to the free list: they can now be written to again metadata_manager.MarkBlocksAsModified(); - unique_lock lock(block_lock); + unique_lock lock(single_file_block_lock); // set the iteration count header.iteration = ++iteration_count; @@ -1139,13 +1256,8 @@ void SingleFileBlockManager::WriteHeader(QueryContext context, DatabaseHeader he set fully_freed_blocks; for (auto &block : modified_blocks) { all_free_blocks.insert(block); - if (!BlockIsRegistered(block)) { - // if the block is no longer registered it is not in use - so it can be re-used after this point - free_list.insert(block); + if (AddFreeBlock(lock, block)) { fully_freed_blocks.insert(block); - } else { - // if the block is still registered it is still in use - keep it in the free_blocks_in_use list - free_blocks_in_use.insert(block); } } auto written_multi_use_blocks = multi_use_blocks; @@ -1190,7 +1302,7 @@ void SingleFileBlockManager::WriteHeader(QueryContext context, DatabaseHeader he header.serialization_compatibility = options.storage_version.GetIndex(); - auto debug_checkpoint_abort = DBConfig::GetSetting(db.GetDatabase()); + auto debug_checkpoint_abort = Settings::Get(db.GetDatabase()); if (debug_checkpoint_abort == CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE) { throw FatalException("Checkpoint aborted after free list write because of PRAGMA checkpoint_abort flag"); } @@ -1234,7 +1346,7 @@ void SingleFileBlockManager::UnregisterBlock(block_id_t id) { // perform the actual unregistration BlockManager::UnregisterBlock(id); // check if it is part of the newly free list - lock_guard lock(block_lock); + lock_guard lock(single_file_block_lock); auto entry = free_blocks_in_use.find(id); if (entry != free_blocks_in_use.end()) { // it is! move it to the regular free list so the block can be re-used diff --git a/src/duckdb/src/storage/standard_buffer_manager.cpp b/src/duckdb/src/storage/standard_buffer_manager.cpp index a90ba37f0..0a6a3da3a 100644 --- a/src/duckdb/src/storage/standard_buffer_manager.cpp +++ b/src/duckdb/src/storage/standard_buffer_manager.cpp @@ -2,6 +2,7 @@ #include "duckdb/common/allocator.hpp" #include "duckdb/common/enums/memory_tag.hpp" +#include "duckdb/common/enums/storage_block_prefetch.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/set.hpp" #include "duckdb/main/attached_database.hpp" @@ -17,12 +18,12 @@ namespace duckdb { #ifdef DUCKDB_DEBUG_DESTROY_BLOCKS static void WriteGarbageIntoBuffer(BlockLock &lock, BlockHandle &block) { - auto &buffer = block.GetBuffer(lock); + auto &buffer = block.GetMemory().GetBuffer(lock); memset(buffer->buffer, 0xa5, buffer->size); // 0xa5 is default memory in debug mode } static void WriteGarbageIntoBuffer(BlockHandle &block) { - auto lock = block.GetLock(); + auto lock = block.GetMemory().GetLock(); WriteGarbageIntoBuffer(lock, block); } #endif @@ -207,47 +208,11 @@ BufferHandle StandardBufferManager::Allocate(MemoryTag tag, idx_t block_size, bo return Pin(block); } -void StandardBufferManager::ReAllocate(shared_ptr &handle, idx_t block_size) { - //! is this function ever used? - D_ASSERT(block_size >= GetBlockSize()); - auto lock = handle->GetLock(); - - auto handle_memory_usage = handle->GetMemoryUsage(); - D_ASSERT(handle->GetState() == BlockState::BLOCK_LOADED); - D_ASSERT(handle_memory_usage == handle->GetBuffer(lock)->AllocSize()); - D_ASSERT(handle_memory_usage == handle->GetMemoryCharge(lock).size); - - auto req = handle->GetBuffer(lock)->CalculateMemory(block_size, handle->block_manager.GetBlockHeaderSize()); - int64_t memory_delta = NumericCast(req.alloc_size) - NumericCast(handle_memory_usage); - - if (memory_delta == 0) { - return; - } else if (memory_delta > 0) { - // evict blocks until we have space to resize this block - // unlock the handle lock during the call to EvictBlocksOrThrow - lock.unlock(); - auto reservation = EvictBlocksOrThrow(handle->GetMemoryTag(), NumericCast(memory_delta), nullptr, - "failed to resize block from %s to %s%s", - StringUtil::BytesToHumanReadableString(handle_memory_usage), - StringUtil::BytesToHumanReadableString(req.alloc_size)); - lock.lock(); - - // EvictBlocks decrements 'current_memory' for us. - handle->MergeMemoryReservation(lock, std::move(reservation)); - } else { - // no need to evict blocks, but we do need to decrement 'current_memory'. - handle->ResizeMemory(lock, req.alloc_size); - } - - handle->ResizeBuffer(lock, block_size, memory_delta); -} - void StandardBufferManager::BatchRead(vector> &handles, const map &load_map, block_id_t first_block, block_id_t last_block) { - auto &block_manager = handles[0]->block_manager; idx_t block_count = NumericCast(last_block - first_block + 1); if (block_count == 1) { - if (DBConfig::GetSetting(db) != StorageBlockPrefetch::DEBUG_FORCE_ALWAYS) { + if (Settings::Get(db) != StorageBlockPrefetch::DEBUG_FORCE_ALWAYS) { // prefetching with block_count == 1 has no performance impact since we can't batch reads // skip the prefetch in this case // we do it anyway if alternative_verify is on for extra testing @@ -255,12 +220,14 @@ void StandardBufferManager::BatchRead(vector> &handles, } } - // allocate a buffer to hold the data of all of the blocks - auto total_block_size = block_count * block_manager.GetBlockAllocSize(); + // Allocate a buffer to hold the data of all blocks. + auto block_alloc_size = handles[0]->GetBlockAllocSize(); + auto total_block_size = block_count * block_alloc_size; auto batch_memory = RegisterMemory(MemoryTag::BASE_TABLE, total_block_size, 0, true); auto intermediate_buffer = Pin(batch_memory); // perform a batch read of the blocks into the buffer + auto &block_manager = handles[0]->GetBlockManager(); block_manager.ReadBlocks(intermediate_buffer.GetFileBuffer(), first_block, block_count); // the blocks are read - now we need to assign them to the individual blocks @@ -271,9 +238,10 @@ void StandardBufferManager::BatchRead(vector> &handles, auto &handle = handles[entry->second]; // reserve memory for the block - idx_t required_memory = handle->GetMemoryUsage(); + auto &block_memory = handle->GetMemory(); + idx_t required_memory = block_memory.GetMemoryUsage(); unique_ptr reusable_buffer; - auto reservation = EvictBlocksOrThrow(handle->GetMemoryTag(), required_memory, &reusable_buffer, + auto reservation = EvictBlocksOrThrow(block_memory.GetMemoryTag(), required_memory, &reusable_buffer, "failed to pin block of size %s%s", StringUtil::BytesToHumanReadableString(required_memory)); // now load the block from the buffer @@ -281,14 +249,13 @@ void StandardBufferManager::BatchRead(vector> &handles, // the prefetching relies on the block handle being pinned again during the actual read before it is evicted BufferHandle buf; { - auto lock = handle->GetLock(); - if (handle->GetState() == BlockState::BLOCK_LOADED) { + auto lock = block_memory.GetLock(); + if (block_memory.GetState() == BlockState::BLOCK_LOADED) { // the block is loaded already by another thread - free up the reservation and continue reservation.Resize(0); continue; } - auto block_ptr = - intermediate_buffer.GetFileBuffer().InternalBuffer() + block_idx * block_manager.GetBlockAllocSize(); + auto block_ptr = intermediate_buffer.GetFileBuffer().InternalBuffer() + block_idx * block_alloc_size; buf = handle->LoadFromBuffer(lock, block_ptr, std::move(reusable_buffer), std::move(reservation)); } } @@ -299,7 +266,7 @@ void StandardBufferManager::Prefetch(vector> &handles) { map to_be_loaded; for (idx_t block_idx = 0; block_idx < handles.size(); block_idx++) { auto &handle = handles[block_idx]; - if (handle->GetState() != BlockState::BLOCK_LOADED) { + if (handle->GetMemory().GetState() != BlockState::BLOCK_LOADED) { // need to load this block - add it to the map to_be_loaded.insert(make_pair(handle->BlockId(), block_idx)); } @@ -344,51 +311,52 @@ BufferHandle StandardBufferManager::Pin(const QueryContext &context, shared_ptr< BufferHandle buf; idx_t required_memory; + auto &block_memory = handle->GetMemory(); { // lock the block - auto lock = handle->GetLock(); + auto lock = block_memory.GetLock(); // check if the block is already loaded - if (handle->GetState() == BlockState::BLOCK_LOADED) { + if (block_memory.GetState() == BlockState::BLOCK_LOADED) { // the block is loaded, increment the reader count and set the BufferHandle buf = handle->Load(context); } - required_memory = handle->GetMemoryUsage(); + required_memory = block_memory.GetMemoryUsage(); } if (buf.IsValid()) { return buf; // the block was already loaded, return it without holding the BlockHandle's lock - } else { - // evict blocks until we have space for the current block - unique_ptr reusable_buffer; - auto reservation = EvictBlocksOrThrow(handle->GetMemoryTag(), required_memory, &reusable_buffer, - "failed to pin block of size %s%s", - StringUtil::BytesToHumanReadableString(required_memory)); + } - // lock the handle again and repeat the check (in case anybody loaded in the meantime) - auto lock = handle->GetLock(); - // check if the block is already loaded - if (handle->GetState() == BlockState::BLOCK_LOADED) { - // the block is loaded, increment the reader count and return a pointer to the handle + // evict blocks until we have space for the current block + unique_ptr reusable_buffer; + auto reservation = + EvictBlocksOrThrow(block_memory.GetMemoryTag(), required_memory, &reusable_buffer, + "failed to pin block of size %s%s", StringUtil::BytesToHumanReadableString(required_memory)); + + // lock the handle again and repeat the check (in case anybody loaded in the meantime) + auto lock = block_memory.GetLock(); + // check if the block is already loaded + if (block_memory.GetState() == BlockState::BLOCK_LOADED) { + // the block is loaded, increment the reader count and return a pointer to the handle + reservation.Resize(0); + buf = handle->Load(context); + } else { + // now we can actually load the current block + D_ASSERT(block_memory.GetReaders() == 0); + buf = handle->Load(context, std::move(reusable_buffer)); + if (!buf.IsValid()) { reservation.Resize(0); - buf = handle->Load(context); - } else { - // now we can actually load the current block - D_ASSERT(handle->Readers() == 0); - buf = handle->Load(context, std::move(reusable_buffer)); - if (!buf.IsValid()) { - reservation.Resize(0); - return buf; // Buffer was destroyed (e.g., due to DestroyBufferUpon::Eviction) - } - auto &memory_charge = handle->GetMemoryCharge(lock); - memory_charge = std::move(reservation); - // in the case of a variable sized block, the buffer may be smaller than a full block. - int64_t delta = NumericCast(handle->GetBuffer(lock)->AllocSize()) - - NumericCast(handle->GetMemoryUsage()); - if (delta) { - handle->ChangeMemoryUsage(lock, delta); - } - D_ASSERT(handle->GetMemoryUsage() == handle->GetBuffer(lock)->AllocSize()); + return buf; // Buffer was destroyed (e.g., due to DestroyBufferUpon::Eviction) + } + auto &memory_charge = block_memory.GetMemoryCharge(lock); + memory_charge = std::move(reservation); + // in the case of a variable sized block, the buffer may be smaller than a full block. + int64_t delta = NumericCast(block_memory.GetBuffer(lock)->AllocSize()) - + NumericCast(block_memory.GetMemoryUsage()); + if (delta) { + block_memory.ChangeMemoryUsage(lock, delta); } + D_ASSERT(block_memory.GetMemoryUsage() == block_memory.GetBuffer(lock)->AllocSize()); } // we should have a valid BufferHandle by now, either because the block was already loaded, or because we loaded it @@ -409,10 +377,10 @@ void StandardBufferManager::VerifyZeroReaders(BlockLock &lock, shared_ptr replacement_buffer; auto &block_allocator = BlockAllocator::Get(db); - auto &buffer = handle->GetBuffer(lock); + auto &buffer = handle->GetMemory().GetBuffer(lock); auto block_header_size = buffer->GetHeaderSize(); auto alloc_size = buffer->AllocSize() - block_header_size; - if (handle->GetBufferType() == FileBufferType::BLOCK) { + if (handle->GetMemory().GetBufferType() == FileBufferType::BLOCK) { auto block = reinterpret_cast(buffer.get()); replacement_buffer = make_uniq(block_allocator, block->id, alloc_size, block_header_size); } else { @@ -427,19 +395,20 @@ void StandardBufferManager::VerifyZeroReaders(BlockLock &lock, shared_ptr &handle) { bool purge = false; + auto &block_memory = handle->GetMemory(); { - auto lock = handle->GetLock(); - if (!handle->GetBuffer(lock) || handle->GetBufferType() == FileBufferType::TINY_BUFFER) { + auto lock = block_memory.GetLock(); + if (!block_memory.GetBuffer(lock) || block_memory.GetBufferType() == FileBufferType::TINY_BUFFER) { return; } - D_ASSERT(handle->Readers() > 0); - auto new_readers = handle->DecrementReaders(); + D_ASSERT(block_memory.GetReaders() > 0); + auto new_readers = block_memory.DecrementReaders(); if (new_readers == 0) { VerifyZeroReaders(lock, handle); - if (handle->MustAddToEvictionQueue()) { + if (block_memory.MustAddToEvictionQueue()) { purge = buffer_pool.AddToEvictionQueue(handle); } else { - handle->Unload(lock); + block_memory.Unload(lock); } } } @@ -494,6 +463,10 @@ void StandardBufferManager::RequireTemporaryDirectory() { } } +bool StandardBufferManager::EncryptTemporaryFiles() { + return Settings::Get(db); +} + void StandardBufferManager::WriteTemporaryBuffer(MemoryTag tag, block_id_t block_id, FileBuffer &buffer) { // WriteTemporaryBuffer assumes that we never write a buffer below DEFAULT_BLOCK_ALLOC_SIZE. RequireTemporaryDirectory(); @@ -510,7 +483,7 @@ void StandardBufferManager::WriteTemporaryBuffer(MemoryTag tag, block_id_t block auto path = GetTemporaryPath(block_id); idx_t header_size = sizeof(idx_t) * 2; - if (db.config.options.temp_file_encryption) { + if (EncryptTemporaryFiles()) { header_size += DEFAULT_ENCRYPTED_BUFFER_HEADER_SIZE; } @@ -527,7 +500,7 @@ void StandardBufferManager::WriteTemporaryBuffer(MemoryTag tag, block_id_t block idx_t offset = sizeof(idx_t) * 2; - if (db.config.options.temp_file_encryption) { + if (EncryptTemporaryFiles()) { uint8_t encryption_metadata[DEFAULT_ENCRYPTED_BUFFER_HEADER_SIZE]; EncryptionEngine::EncryptTemporaryBuffer(db, buffer.InternalBuffer(), buffer.AllocSize(), encryption_metadata); //! Write the nonce (and tag for GCM). @@ -548,7 +521,14 @@ unique_ptr StandardBufferManager::ReadTemporaryBuffer(QueryContext c } if (temporary_directory.handle->GetTempFile().HasTemporaryBuffer(id)) { // This is a block that was offloaded to a regular .tmp file, the file contains blocks of a fixed size - return temporary_directory.handle->GetTempFile().ReadTemporaryBuffer(context, id, std::move(reusable_buffer)); + + auto buffer = + temporary_directory.handle->GetTempFile().ReadTemporaryBuffer(context, id, std::move(reusable_buffer)); + + // Decrement evicted size. + evicted_data_per_tag[uint8_t(tag)] -= buffer->AllocSize(); + + return buffer; } // This block contains data of variable size so we need to open it and read it to get its size. @@ -565,7 +545,7 @@ unique_ptr StandardBufferManager::ReadTemporaryBuffer(QueryContext c // Allocate a buffer of the file's size and read the data into that buffer. auto buffer = ConstructManagedBuffer(block_size, block_header_size, std::move(reusable_buffer)); - if (db.config.options.temp_file_encryption) { + if (EncryptTemporaryFiles()) { // encrypted //! Read nonce and tag from file. uint8_t encryption_metadata[DEFAULT_ENCRYPTED_BUFFER_HEADER_SIZE]; @@ -583,12 +563,19 @@ unique_ptr StandardBufferManager::ReadTemporaryBuffer(QueryContext c handle.reset(); // Delete the file and return the buffer. - DeleteTemporaryFile(block); + DeleteTemporaryFile(block.GetMemory()); + + // Decrement evicted size. + evicted_data_per_tag[uint8_t(tag)] -= buffer->AllocSize(); + return buffer; } -void StandardBufferManager::DeleteTemporaryFile(BlockHandle &block) { - auto id = block.BlockId(); +void StandardBufferManager::DeleteTemporaryFile(BlockMemory &memory) { + if (!memory.IsUnloaded()) { + return; + } + auto id = memory.BlockId(); if (temporary_directory.path.empty()) { // no temporary directory specified: nothing to delete return; @@ -604,7 +591,7 @@ void StandardBufferManager::DeleteTemporaryFile(BlockHandle &block) { // check if we should delete the file from the shared pool of files, or from the general file system if (temporary_directory.handle->GetTempFile().HasTemporaryBuffer(id)) { idx_t eviction_size = temporary_directory.handle->GetTempFile().DeleteTemporaryBuffer(id); - evicted_data_per_tag[uint8_t(block.GetMemoryTag())] -= eviction_size; + evicted_data_per_tag[uint8_t(memory.GetMemoryTag())] -= eviction_size; return; } @@ -612,7 +599,7 @@ void StandardBufferManager::DeleteTemporaryFile(BlockHandle &block) { auto &fs = FileSystem::GetFileSystem(db); auto path = GetTemporaryPath(id); if (fs.FileExists(path)) { - evicted_data_per_tag[uint8_t(block.GetMemoryTag())] -= block.GetMemoryUsage(); + evicted_data_per_tag[uint8_t(memory.GetMemoryTag())] -= memory.GetMemoryUsage(); auto handle = fs.OpenFile(path, FileFlags::FILE_FLAGS_READ); auto content_size = handle->GetFileSize(); handle.reset(); diff --git a/src/duckdb/src/storage/statistics/base_statistics.cpp b/src/duckdb/src/storage/statistics/base_statistics.cpp index 176045148..54c3a7b11 100644 --- a/src/duckdb/src/storage/statistics/base_statistics.cpp +++ b/src/duckdb/src/storage/statistics/base_statistics.cpp @@ -269,6 +269,8 @@ unique_ptr BaseStatistics::PushdownExtract(const StorageIndex &i switch (stats_type) { case StatisticsType::STRUCT_STATS: return StructStats::PushdownExtract(*this, index); + case StatisticsType::VARIANT_STATS: + return VariantStats::PushdownExtract(*this, index); default: throw InternalException("PushdownExtract not supported for StatisticsType::%s", EnumUtil::ToString(stats_type)); } @@ -346,7 +348,7 @@ void BaseStatistics::CombineValidity(const BaseStatistics &left, const BaseStati has_no_null = left.has_no_null || right.has_no_null; } -void BaseStatistics::CopyValidity(BaseStatistics &stats) { +void BaseStatistics::CopyValidity(const BaseStatistics &stats) { has_null = stats.has_null; has_no_null = stats.has_no_null; } diff --git a/src/duckdb/src/storage/statistics/geometry_stats.cpp b/src/duckdb/src/storage/statistics/geometry_stats.cpp index 91ebeaa5f..f2f7fae6b 100644 --- a/src/duckdb/src/storage/statistics/geometry_stats.cpp +++ b/src/duckdb/src/storage/statistics/geometry_stats.cpp @@ -98,6 +98,9 @@ void GeometryStats::Serialize(const BaseStatistics &stats, Serializer &serialize types.WriteProperty(103, "types_xym", data.types.sets[2]); types.WriteProperty(104, "types_xyzm", data.types.sets[3]); }); + + // Write flags + serializer.WritePropertyWithDefault(202, "flags", data.flags.flags); } void GeometryStats::Deserialize(Deserializer &deserializer, BaseStatistics &base) { @@ -122,6 +125,9 @@ void GeometryStats::Deserialize(Deserializer &deserializer, BaseStatistics &base types.ReadProperty(103, "types_xym", data.types.sets[2]); types.ReadProperty(104, "types_xyzm", data.types.sets[3]); }); + + // Read flags + deserializer.ReadPropertyWithDefault(202, "flags", data.flags.flags); } string GeometryStats::ToString(const BaseStatistics &stats) { @@ -129,10 +135,14 @@ string GeometryStats::ToString(const BaseStatistics &stats) { string result; result += "["; - result += StringUtil::Format("Extent: [X: [%f, %f], Y: [%f, %f], Z: [%f, %f], M: [%f, %f]", data.extent.x_min, + result += StringUtil::Format("Extent: [X: [%f, %f], Y: [%f, %f], Z: [%f, %f], M: [%f, %f]]", data.extent.x_min, data.extent.x_max, data.extent.y_min, data.extent.y_max, data.extent.z_min, data.extent.z_max, data.extent.m_min, data.extent.m_max); - result += StringUtil::Format("], Types: [%s]", StringUtil::Join(data.types.ToString(true), ", ")); + result += StringUtil::Format(", Types: [%s]", StringUtil::Join(data.types.ToString(true), ", ")); + result += StringUtil::Format( + ", Flags: [Has Empty Geom: %s, Has No Empty Geom: %s, Has Empty Part: %s, Has No Empty Part: %s]", + data.flags.HasEmptyGeometry() ? "true" : "false", data.flags.HasNonEmptyGeometry() ? "true" : "false", + data.flags.HasEmptyPart() ? "true" : "false", data.flags.HasNonEmptyPart() ? "true" : "false"); result += "]"; return result; @@ -178,6 +188,10 @@ GeometryTypeSet &GeometryStats::GetTypes(BaseStatistics &stats) { return GetDataUnsafe(stats).types; } +GeometryStatsFlags &GeometryStats::GetFlags(BaseStatistics &stats) { + return GetDataUnsafe(stats).flags; +} + const GeometryExtent &GeometryStats::GetExtent(const BaseStatistics &stats) { return GetDataUnsafe(stats).extent; } @@ -186,6 +200,10 @@ const GeometryTypeSet &GeometryStats::GetTypes(const BaseStatistics &stats) { return GetDataUnsafe(stats).types; } +const GeometryStatsFlags &GeometryStats::GetFlags(const BaseStatistics &stats) { + return GetDataUnsafe(stats).flags; +} + // Expression comparison pruning static FilterPropagateResult CheckIntersectionFilter(const GeometryStatsData &data, const Value &constant) { if (constant.IsNull() || constant.type().id() != LogicalTypeId::GEOMETRY) { diff --git a/src/duckdb/src/storage/statistics/numeric_stats.cpp b/src/duckdb/src/storage/statistics/numeric_stats.cpp index 225524406..bc119f583 100644 --- a/src/duckdb/src/storage/statistics/numeric_stats.cpp +++ b/src/duckdb/src/storage/statistics/numeric_stats.cpp @@ -624,4 +624,6 @@ void NumericStats::Verify(const BaseStatistics &stats, Vector &vector, const Sel } } +template uint32_t NumericStats::GetMinUnsafe(const BaseStatistics &stats); +template uint32_t NumericStats::GetMaxUnsafe(const BaseStatistics &stats); } // namespace duckdb diff --git a/src/duckdb/src/storage/statistics/variant_stats.cpp b/src/duckdb/src/storage/statistics/variant_stats.cpp index d36f2573f..853257574 100644 --- a/src/duckdb/src/storage/statistics/variant_stats.cpp +++ b/src/duckdb/src/storage/statistics/variant_stats.cpp @@ -62,6 +62,28 @@ BaseStatistics &VariantStats::GetUnshreddedStats(BaseStatistics &stats) { return stats.child_stats[0]; } +const BaseStatistics &VariantStats::GetTypedStats(const BaseStatistics &stats) { + if (stats.GetType().id() != LogicalTypeId::STRUCT) { + // primitive stats - return the stats directly + return stats; + } + // STRUCT(typed_value, (untyped_value)) - return the typed_value stats + return StructStats::GetChildStats(stats, TYPED_VALUE_INDEX); +} + +optional_ptr VariantStats::GetUntypedStats(const BaseStatistics &stats) { + if (stats.GetType().id() != LogicalTypeId::STRUCT) { + // primitive stats - no untyped stats + return nullptr; + } + // STRUCT(typed_value, (untyped_value)) - check if we have untyped stats + if (StructType::GetChildCount(stats.GetType()) == 1) { + // fully shredded and no untyped stats + return nullptr; + } + return StructStats::GetChildStats(stats, UNTYPED_VALUE_INDEX); +} + void VariantStats::SetUnshreddedStats(BaseStatistics &stats, const BaseStatistics &new_stats) { AssertVariant(stats); stats.child_stats[0].Copy(new_stats); @@ -89,35 +111,96 @@ void VariantStats::MarkAsNotShredded(BaseStatistics &stats) { //===--------------------------------------------------------------------===// static void AssertShreddedStats(const BaseStatistics &stats) { - if (stats.GetType().id() != LogicalTypeId::STRUCT) { - throw InternalException("Shredded stats should be of type STRUCT, not %s", - EnumUtil::ToString(stats.GetType().id())); + auto &stats_type = stats.GetType(); + if (stats_type.id() != LogicalTypeId::STRUCT) { + // primitive stats - this is fine + return; } - auto &struct_children = StructType::GetChildTypes(stats.GetType()); - if (struct_children.size() != 2) { - throw InternalException( - "Shredded stats need to consist of 2 children, 'untyped_value_index' and 'typed_value', not: %s", - stats.GetType().ToString()); + auto &struct_children = StructType::GetChildTypes(stats_type); + if (struct_children.size() > 2 || struct_children[VariantStats::TYPED_VALUE_INDEX].first != "typed_value") { + throw InternalException("Shredded stats need to consist of 1 or 2 children, 'typed_value' and optionally " + "'untyped_value_index', not: %s", + stats.GetType().ToString()); + } + + if (struct_children.size() == 2) { + auto &untyped_entry = struct_children[VariantStats::UNTYPED_VALUE_INDEX]; + if (untyped_entry.first != "untyped_value_index") { + throw InternalException("Untyped value index entry should be called \"untyped_value_index\""); + } + if (untyped_entry.second.id() != LogicalTypeId::UINTEGER) { + throw InternalException("Shredded stats 'untyped_value_index' should be of type UINTEGER, not %s", + EnumUtil::ToString(untyped_entry.second.id())); + } } - if (struct_children[0].second.id() != LogicalTypeId::UINTEGER) { - throw InternalException("Shredded stats 'untyped_value_index' should be of type UINTEGER, not %s", - EnumUtil::ToString(struct_children[0].second.id())); +} + +optional_ptr VariantShreddedStats::FindChildStats(const BaseStatistics &stats, + const VariantPathComponent &component) { + const_reference typed_value_stats_ref(stats); + const_reference typed_value_type_ref(stats.GetType()); + if (typed_value_type_ref.get().IsNested()) { + // "typed_value" / "untyped_value" + AssertShreddedStats(stats); + + typed_value_stats_ref = StructStats::GetChildStats(stats, VariantStats::TYPED_VALUE_INDEX); + typed_value_type_ref = typed_value_stats_ref.get().GetType(); + } + auto &typed_value_stats = typed_value_stats_ref.get(); + auto &typed_value_type = typed_value_type_ref.get(); + + switch (component.lookup_mode) { + case VariantChildLookupMode::BY_INDEX: { + if (typed_value_type.id() != LogicalTypeId::LIST) { + return nullptr; + } + auto &child_stats = ListStats::GetChildStats(typed_value_stats); + return child_stats; + } + case VariantChildLookupMode::BY_KEY: { + if (typed_value_type.id() != LogicalTypeId::STRUCT) { + return nullptr; + } + auto &object_fields = StructType::GetChildTypes(typed_value_type); + for (idx_t i = 0; i < object_fields.size(); i++) { + auto &object_field = object_fields[i]; + if (StringUtil::CIEquals(object_field.first, component.key)) { + return StructStats::GetChildStats(typed_value_stats, i); + } + } + return nullptr; + } + default: + throw InternalException("VariantChildLookupMode::%s not implemented for FindShreddedStats", + EnumUtil::ToString(component.lookup_mode)); } } bool VariantShreddedStats::IsFullyShredded(const BaseStatistics &stats) { + auto &stats_type = stats.GetType(); + if (!stats_type.IsNested()) { + // if this is a primitive type this is fully nested + return true; + } AssertShreddedStats(stats); + if (StructType::GetChildCount(stats_type) == 1) { + // we don't have untyped values - this must be fully shredded + return true; + } - auto &untyped_value_index_stats = StructStats::GetChildStats(stats, 0); - auto &typed_value_stats = StructStats::GetChildStats(stats, 1); + auto &typed_value_stats = StructStats::GetChildStats(stats, VariantStats::TYPED_VALUE_INDEX); + auto &untyped_value_index_stats = StructStats::GetChildStats(stats, VariantStats::UNTYPED_VALUE_INDEX); if (!typed_value_stats.CanHaveNull()) { //! Fully shredded, no nulls return true; } if (!untyped_value_index_stats.CanHaveNoNull()) { - //! In the event that this field is entirely missing from the parent OBJECT, both are NULL - return false; + //! In the event that the untyped_value_index is entirely NULL, all values are NULL Variant values + //! But that doesn't mean we can't do pushdown into this field, so it is shredded (only when the extract path + //! ends at the parent we can't do pushdown) + D_ASSERT(untyped_value_index_stats.CanHaveNull()); + return true; } if (!NumericStats::HasMin(untyped_value_index_stats) || !NumericStats::HasMax(untyped_value_index_stats)) { //! Has no min/max values, essentially double-checking the CanHaveNoNull from above @@ -129,21 +212,35 @@ bool VariantShreddedStats::IsFullyShredded(const BaseStatistics &stats) { //! Not a constant return false; } - //! 0 is reserved for NULL Variant values + //! 0 is reserved for missing values (field absent from parent object) return min_value == 0; } LogicalType ToStructuredType(const LogicalType &shredding) { + if (shredding.id() != LogicalTypeId::STRUCT) { + // not a struct - this is a primitive type + return shredding; + } D_ASSERT(shredding.id() == LogicalTypeId::STRUCT); auto &child_types = StructType::GetChildTypes(shredding); - D_ASSERT(child_types.size() == 2); + D_ASSERT(child_types.size() <= 2); - auto &typed_value = child_types[1].second; + auto &typed_value = child_types[VariantStats::TYPED_VALUE_INDEX].second; if (typed_value.id() == LogicalTypeId::STRUCT) { auto &struct_children = StructType::GetChildTypes(typed_value); child_list_t structured_children; - for (auto &child : struct_children) { + vector indices(struct_children.size()); + for (idx_t i = 0; i < indices.size(); i++) { + indices[i] = i; + } + std::sort(indices.begin(), indices.end(), [&](const idx_t &lhs, const idx_t &rhs) { + auto &a = struct_children[lhs].first; + auto &b = struct_children[rhs].first; + return a < b; + }); + for (auto &index : indices) { + auto &child = struct_children[index]; structured_children.emplace_back(child.first, ToStructuredType(child.second)); } return LogicalType::STRUCT(structured_children); @@ -265,7 +362,7 @@ static string ToStringInternal(const BaseStatistics &stats) { string result; result = StringUtil::Format("fully_shredded: %s", VariantShreddedStats::IsFullyShredded(stats) ? "true" : "false"); - auto &typed_value = StructStats::GetChildStats(stats, 1); + auto &typed_value = StructStats::GetChildStats(stats, VariantStats::TYPED_VALUE_INDEX); auto type_id = typed_value.GetType().id(); if (type_id == LogicalTypeId::LIST) { result += ", child: "; @@ -274,12 +371,22 @@ static string ToStringInternal(const BaseStatistics &stats) { } else if (type_id == LogicalTypeId::STRUCT) { result += ", children: {"; auto &fields = StructType::GetChildTypes(typed_value.GetType()); - for (idx_t i = 0; i < fields.size(); i++) { + vector indices(fields.size()); + for (idx_t i = 0; i < indices.size(); i++) { + indices[i] = i; + } + std::sort(indices.begin(), indices.end(), [&](const idx_t &lhs, const idx_t &rhs) { + auto &a = fields[lhs].first; + auto &b = fields[rhs].first; + return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + }); + for (idx_t i = 0; i < indices.size(); i++) { if (i) { result += ", "; } - auto &child_stats = StructStats::GetChildStats(typed_value, i); - result += StringUtil::Format("%s: %s", fields[i].first, ToStringInternal(child_stats)); + auto &child_stats = StructStats::GetChildStats(typed_value, indices[i]); + auto &field = fields[indices[i]]; + result += StringUtil::Format("%s: %s", field.first, ToStringInternal(child_stats)); } result += "}"; } @@ -300,41 +407,76 @@ string VariantStats::ToString(const BaseStatistics &stats) { return result; } -static BaseStatistics WrapTypedValue(BaseStatistics &untyped_value_index, BaseStatistics &typed_value) { - BaseStatistics shredded = BaseStatistics::CreateEmpty(LogicalType::STRUCT( - {{"untyped_value_index", untyped_value_index.GetType()}, {"typed_value", typed_value.GetType()}})); +static BaseStatistics WrapTypedValue(const BaseStatistics &typed_value, + optional_ptr untyped_value_index) { + if (!untyped_value_index && !typed_value.GetType().IsNested()) { + // no untyped value and not a nested type - directly emit the typed stats + return typed_value.Copy(); + } + child_list_t stats_type; + stats_type.emplace_back(make_pair("typed_value", typed_value.GetType())); + if (untyped_value_index) { + stats_type.emplace_back(make_pair("untyped_value_index", untyped_value_index->GetType())); + } + BaseStatistics shredded = BaseStatistics::CreateEmpty(LogicalType::STRUCT(std::move(stats_type))); - StructStats::GetChildStats(shredded, 0).Copy(untyped_value_index); - StructStats::GetChildStats(shredded, 1).Copy(typed_value); + StructStats::GetChildStats(shredded, VariantStats::TYPED_VALUE_INDEX).Copy(typed_value); + if (untyped_value_index) { + StructStats::GetChildStats(shredded, VariantStats::UNTYPED_VALUE_INDEX).Copy(*untyped_value_index); + } return shredded; } -bool VariantStats::MergeShredding(BaseStatistics &stats, const BaseStatistics &other, BaseStatistics &new_stats) { +unique_ptr VariantStats::WrapExtractedFieldAsVariant(const BaseStatistics &base_variant, + const BaseStatistics &extracted_field) { + D_ASSERT(base_variant.type.id() == LogicalTypeId::VARIANT); + AssertShreddedStats(extracted_field); + + BaseStatistics copy = BaseStatistics::CreateUnknown(base_variant.GetType()); + copy.Copy(base_variant); + copy.child_stats[1] = BaseStatistics::CreateUnknown(extracted_field.GetType()); + copy.child_stats[1].Copy(extracted_field); + return copy.ToUnique(); +} + +bool VariantStats::MergeShredding(const BaseStatistics &stats, const BaseStatistics &other, BaseStatistics &new_stats) { //! shredded_type: - //! STRUCT(untyped_value_index UINTEGER, typed_value ) + //! + //! STRUCT(typed_value ) + //! STRUCT(typed_value , untyped_value_index UINTEGER) //! shredding, 1 of: //! - //! - //! - [] - D_ASSERT(stats.type.id() == LogicalTypeId::STRUCT); - D_ASSERT(other.type.id() == LogicalTypeId::STRUCT); - - auto &stats_children = StructType::GetChildTypes(stats.type); - auto &other_children = StructType::GetChildTypes(other.type); - D_ASSERT(stats_children.size() == 2); - D_ASSERT(other_children.size() == 2); - - auto &stats_typed_value_type = stats_children[1].second; - auto &other_typed_value_type = other_children[1].second; - - //! Merge the untyped_value_index stats - auto &untyped_value_index = StructStats::GetChildStats(stats, 0); - untyped_value_index.Merge(StructStats::GetChildStats(other, 0)); - - auto &stats_typed_value = StructStats::GetChildStats(stats, 1); - auto &other_typed_value = StructStats::GetChildStats(other, 1); + auto &stats_typed_value = GetTypedStats(stats); + auto &other_typed_value = GetTypedStats(other); + + auto &stats_typed_value_type = stats_typed_value.GetType(); + auto &other_typed_value_type = other_typed_value.GetType(); + + auto untyped_value_stats = GetUntypedStats(stats); + auto other_untyped_stats = GetUntypedStats(other); + + // handle untyped value stats + optional_ptr new_untyped_value_stats; + BaseStatistics owned_untyped_value_stats; + + if (untyped_value_stats && other_untyped_stats) { + // both entries have untyped value stats - merge them + owned_untyped_value_stats = untyped_value_stats->Copy(); + owned_untyped_value_stats.Merge(*other_untyped_stats); + new_untyped_value_stats = owned_untyped_value_stats; + } else if (untyped_value_stats) { + // only LHS has untyped value stats + owned_untyped_value_stats = untyped_value_stats->Copy(); + new_untyped_value_stats = owned_untyped_value_stats; + } else if (other_untyped_stats) { + // only RHS has untyped value stats + owned_untyped_value_stats = other_untyped_stats->Copy(); + new_untyped_value_stats = owned_untyped_value_stats; + } if (stats_typed_value_type.id() == LogicalTypeId::STRUCT) { if (stats_typed_value_type.id() != other_typed_value_type.id()) { @@ -389,7 +531,7 @@ bool VariantStats::MergeShredding(BaseStatistics &stats, const BaseStatistics &o StructStats::SetChildStats(new_typed_value, i, new_child_stats[i]); } new_typed_value.CombineValidity(stats_typed_value, other_typed_value); - new_stats = WrapTypedValue(untyped_value_index, new_typed_value); + new_stats = WrapTypedValue(new_typed_value, new_untyped_value_stats); return true; } else if (stats_typed_value_type.id() == LogicalTypeId::LIST) { if (stats_typed_value_type.id() != other_typed_value_type.id()) { @@ -407,7 +549,7 @@ bool VariantStats::MergeShredding(BaseStatistics &stats, const BaseStatistics &o auto new_typed_value = BaseStatistics::CreateEmpty(LogicalType::LIST(new_child_stats.type)); new_typed_value.CombineValidity(stats_typed_value, other_typed_value); ListStats::SetChildStats(new_typed_value, new_child_stats.ToUnique()); - new_stats = WrapTypedValue(untyped_value_index, new_typed_value); + new_stats = WrapTypedValue(new_typed_value, new_untyped_value_stats); return true; } else { D_ASSERT(!stats_typed_value_type.IsNested()); @@ -415,8 +557,9 @@ bool VariantStats::MergeShredding(BaseStatistics &stats, const BaseStatistics &o //! other is not the same type, can't merge return false; } - stats_typed_value.Merge(other_typed_value); - new_stats = std::move(stats); + auto new_typed_stats = stats_typed_value.Copy(); + new_typed_stats.Merge(other_typed_value); + new_stats = WrapTypedValue(new_typed_stats, new_untyped_value_stats); return true; } } @@ -522,4 +665,58 @@ VariantStatsData &VariantStats::GetDataUnsafe(BaseStatistics &stats) { return stats.stats_union.variant_data; } +static bool CanUseShreddedStats(optional_ptr shredded_stats) { + return shredded_stats && VariantShreddedStats::IsFullyShredded(*shredded_stats); +} + +unique_ptr VariantStats::PushdownExtract(const BaseStatistics &stats, const StorageIndex &index) { + if (!VariantStats::IsShredded(stats)) { + //! Not shredded at all, no stats available + return nullptr; + } + + optional_ptr res(VariantStats::GetShreddedStats(stats)); + if (!CanUseShreddedStats(res)) { + //! Not fully shredded, can't say anything meaningful about the stats + return nullptr; + } + + reference index_iter(index); + while (true) { + auto ¤t = index_iter.get(); + D_ASSERT(!current.HasPrimaryIndex()); + auto &field_name = current.GetFieldName(); + VariantPathComponent path(field_name); + res = VariantShreddedStats::FindChildStats(*res, path); + if (!CanUseShreddedStats(res)) { + //! Not fully shredded, can't say anything meaningful about the stats + return nullptr; + } + if (!index_iter.get().HasChildren()) { + break; + } + } + auto &shredded_child_stats = *res; + + auto &typed_value_stats = GetTypedStats(shredded_child_stats); + auto &last_index = index_iter.get(); + auto &child_type = typed_value_stats.type; + if (!last_index.HasType() || last_index.GetType().id() == LogicalTypeId::VARIANT) { + //! Return the variant stats, not the 'typed_value' (non-variant) stats, since there's no cast pushed down + return WrapExtractedFieldAsVariant(stats, shredded_child_stats); + } + if (!VariantShreddedStats::IsFullyShredded(shredded_child_stats)) { + //! Not all data is shredded, so there are values in the column that are not of the shredded type + return nullptr; + } + + auto &cast_type = last_index.GetType(); + if (child_type != cast_type) { + //! FIXME: support try_cast + return StatisticsPropagator::TryPropagateCast(typed_value_stats, child_type, cast_type); + } + auto result = typed_value_stats.ToUnique(); + return result; +} + } // namespace duckdb diff --git a/src/duckdb/src/storage/storage_index.cpp b/src/duckdb/src/storage/storage_index.cpp new file mode 100644 index 000000000..00a77fba8 --- /dev/null +++ b/src/duckdb/src/storage/storage_index.cpp @@ -0,0 +1,109 @@ +#include "duckdb/storage/storage_index.hpp" + +namespace duckdb { + +StorageIndex::StorageIndex() + : has_index(true), index(COLUMN_IDENTIFIER_ROW_ID), index_type(StorageIndexType::FULL_READ) { +} +StorageIndex::StorageIndex(idx_t index) : has_index(true), index(index), index_type(StorageIndexType::FULL_READ) { +} +StorageIndex::StorageIndex(const string &field) + : has_index(false), field(field), index_type(StorageIndexType::FULL_READ) { +} +StorageIndex::StorageIndex(idx_t index, vector child_indexes_p) + : has_index(true), index(index), index_type(StorageIndexType::FULL_READ), + child_indexes(std::move(child_indexes_p)) { +} +StorageIndex::StorageIndex(const string &field, vector child_indexes_p) + : has_index(false), field(field), index_type(StorageIndexType::FULL_READ), + child_indexes(std::move(child_indexes_p)) { +} + +StorageIndex StorageIndex::FromColumnIndex(const ColumnIndex &column_id) { + vector result; + for (auto &child_id : column_id.GetChildIndexes()) { + result.push_back(StorageIndex::FromColumnIndex(child_id)); + } + StorageIndex storage_index; + if (column_id.HasPrimaryIndex()) { + storage_index = StorageIndex(column_id.GetPrimaryIndex(), std::move(result)); + } else { + storage_index = StorageIndex(column_id.GetFieldName(), std::move(result)); + } + if (column_id.HasType()) { + storage_index.SetType(column_id.GetType()); + } + if (column_id.IsPushdownExtract()) { + storage_index.SetPushdownExtract(); + } + return storage_index; +} + +bool StorageIndex::HasPrimaryIndex() const { + return has_index; +} +idx_t StorageIndex::GetPrimaryIndex() const { + D_ASSERT(has_index); + return index; +} +const string &StorageIndex::GetFieldName() const { + D_ASSERT(!has_index); + return field; +} +PhysicalIndex StorageIndex::ToPhysical() const { + D_ASSERT(has_index); + return PhysicalIndex(index); +} +bool StorageIndex::HasType() const { + return type.id() != LogicalTypeId::INVALID; +} +const LogicalType &StorageIndex::GetScanType() const { + D_ASSERT(HasType()); + if (IsPushdownExtract()) { + return child_indexes[0].GetScanType(); + } + return GetType(); +} +const LogicalType &StorageIndex::GetType() const { + return type; +} +bool StorageIndex::HasChildren() const { + return !child_indexes.empty(); +} +idx_t StorageIndex::ChildIndexCount() const { + return child_indexes.size(); +} +const StorageIndex &StorageIndex::GetChildIndex(idx_t idx) const { + return child_indexes[idx]; +} +StorageIndex &StorageIndex::GetChildIndex(idx_t idx) { + return child_indexes[idx]; +} +const vector &StorageIndex::GetChildIndexes() const { + return child_indexes; +} +void StorageIndex::AddChildIndex(StorageIndex new_index) { + this->child_indexes.push_back(std::move(new_index)); +} +void StorageIndex::SetType(const LogicalType &type_information) { + type = type_information; +} +void StorageIndex::SetPushdownExtract() { + D_ASSERT(!IsPushdownExtract()); + index_type = StorageIndexType::PUSHDOWN_EXTRACT; +} +bool StorageIndex::IsPushdownExtract() const { + return index_type == StorageIndexType::PUSHDOWN_EXTRACT; +} +void StorageIndex::SetIndex(idx_t new_index) { + D_ASSERT(has_index); + index = new_index; +} +bool StorageIndex::IsRowIdColumn() const { + if (!has_index) { + return false; + } + return index == DConstants::INVALID_INDEX; +} + +} // namespace duckdb diff --git a/src/duckdb/src/storage/storage_info.cpp b/src/duckdb/src/storage/storage_info.cpp index ce7c3fb07..6138cc0bc 100644 --- a/src/duckdb/src/storage/storage_info.cpp +++ b/src/duckdb/src/storage/storage_info.cpp @@ -8,10 +8,11 @@ constexpr idx_t Storage::MAX_ROW_GROUP_SIZE; constexpr idx_t Storage::MAX_BLOCK_ALLOC_SIZE; constexpr idx_t Storage::MIN_BLOCK_ALLOC_SIZE; constexpr idx_t Storage::DEFAULT_BLOCK_HEADER_SIZE; +constexpr uint64_t MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH; const uint64_t VERSION_NUMBER = 64; const uint64_t VERSION_NUMBER_LOWER = 64; -const uint64_t VERSION_NUMBER_UPPER = 67; +const uint64_t VERSION_NUMBER_UPPER = 68; static_assert(VERSION_NUMBER_LOWER <= VERSION_NUMBER, "Check on VERSION_NUMBER lower bound"); static_assert(VERSION_NUMBER <= VERSION_NUMBER_UPPER, "Check on VERSION_NUMBER upper bound"); @@ -91,7 +92,7 @@ static const StorageVersionInfo storage_version_info[] = { {"v1.4.2", 67}, {"v1.4.3", 67}, {"v1.4.4", 67}, - {"v1.5.0", 67}, + {"v1.5.0", 68}, {nullptr, 0} }; // END OF STORAGE VERSION INFO diff --git a/src/duckdb/src/storage/storage_manager.cpp b/src/duckdb/src/storage/storage_manager.cpp index 29d42ec7f..45fbd6abc 100644 --- a/src/duckdb/src/storage/storage_manager.cpp +++ b/src/duckdb/src/storage/storage_manager.cpp @@ -5,6 +5,7 @@ #include "duckdb/main/attached_database.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/client_data.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/main/database.hpp" #include "duckdb/storage/checkpoint_manager.hpp" #include "duckdb/storage/in_memory_block_manager.hpp" @@ -20,10 +21,67 @@ #include "mbedtls_wrapper.hpp" namespace duckdb { - using SHA256State = duckdb_mbedtls::MbedTlsWrapper::SHA256State; -void StorageOptions::Initialize(const unordered_map &options) { +void StorageOptions::SetEncryptionVersion(string &storage_version_user_provided) { + // storage version < v1.4.0 + if (!storage_version.IsValid() || + storage_version.GetIndex() < SerializationCompatibility::FromString("v1.4.0").serialization_version) { + if (!storage_version_user_provided.empty()) { + throw InvalidInputException("Explicit provided STORAGE_VERSION (\"%s\") and ENCRYPTION_KEY (storage >= " + "v1.4.0) are not compatible", + storage_version_user_provided); + } + } + + auto target_encryption_version = encryption_version; + + if (target_encryption_version == EncryptionTypes::NONE) { + target_encryption_version = EncryptionTypes::V0_1; + } + + switch (target_encryption_version) { + case EncryptionTypes::V0_1: + // storage version not explicitly set + if (!storage_version.IsValid() && storage_version_user_provided.empty()) { + storage_version = SerializationCompatibility::FromString("v1.5.0").serialization_version; + break; + } + // storage version set, but v1.4.0 =< storage < v1.5.0 + if (storage_version.GetIndex() < SerializationCompatibility::FromString("v1.5.0").serialization_version) { + if (!storage_version_user_provided.empty()) { + if (encryption_version == target_encryption_version) { + // encryption version is explicitly given, but not compatible with < v1.5.0 + throw InvalidInputException("Explicit provided STORAGE_VERSION (\"%s\") is not compatible with " + "'debug_encryption_version = v1' (storage >= " + "v1.5.0)", + storage_version_user_provided); + } + } else { + // encryption version needs to be lowered, because storage version < v1.5.0 + target_encryption_version = EncryptionTypes::V0_0; + break; + } + } + + break; + + case EncryptionTypes::V0_0: + // we set this to V0 to V1.5.0 if no explicit storage version provided + if (!storage_version.IsValid() && storage_version_user_provided.empty()) { + storage_version = SerializationCompatibility::FromString("v1.5.0").serialization_version; + break; + } + // if storage version is provided, we do nothing + break; + default: + throw InvalidConfigurationException("Encryption version is not set"); + } + + encryption_version = target_encryption_version; +} + +void StorageOptions::Initialize(unordered_map &options) { string storage_version_user_provided = ""; for (auto &entry : options) { if (entry.first == "block_size") { @@ -61,24 +119,21 @@ void StorageOptions::Initialize(const unordered_map &options) { } else { compress_in_memory = CompressInMemory::DO_NOT_COMPRESS; } + } else if (entry.first == "debug_encryption_version") { + encryption_version = EncryptionTypes::StringToVersion(entry.second.ToString()); } else { throw BinderException("Unrecognized option for attach \"%s\"", entry.first); } } - if (encryption && - (!storage_version.IsValid() || - storage_version.GetIndex() < SerializationCompatibility::FromString("v1.4.0").serialization_version)) { - if (!storage_version_user_provided.empty()) { - throw InvalidInputException( - "Explicit provided STORAGE_VERSION (\"%s\") and ENCRYPTION_KEY (storage >= v1.4.0) are not compatible", - storage_version_user_provided); - } - // set storage version to v1.4.0 - storage_version = SerializationCompatibility::FromString("v1.4.0").serialization_version; + // erase encryption settings + options.erase("encryption_key"); + options.erase("encryption_cipher"); + if (encryption) { + SetEncryptionVersion(storage_version_user_provided); } } -StorageManager::StorageManager(AttachedDatabase &db, string path_p, const AttachOptions &options) +StorageManager::StorageManager(AttachedDatabase &db, string path_p, AttachOptions &options) : db(db), path(std::move(path_p)), read_only(options.access_mode == AccessMode::READ_ONLY), wal_size(0) { if (path.empty()) { path = IN_MEMORY_PATH; @@ -120,6 +175,18 @@ void StorageManager::SetWALSize(idx_t size) { wal_size = size; } +idx_t StorageManager::GetWALEntriesCount() const { + return wal_entries_count; +} + +void StorageManager::ResetWALEntriesCount() { + wal_entries_count = 0; +} + +void StorageManager::IncrementWALEntriesCount() { + wal_entries_count++; +} + optional_ptr StorageManager::GetWAL() { if (InMemory() || read_only || !load_complete) { return nullptr; @@ -135,7 +202,11 @@ bool StorageManager::HasWAL() const { } bool StorageManager::WALStartCheckpoint(MetaBlockPointer meta_block, CheckpointOptions &options) { - lock_guard guard(wal_lock); + unique_ptr> guard; + if (!options.wal_lock) { + // not holding the WAL lock yet - grab it + guard = GetWALLock(); + } // while holding the WAL lock - get the last committed transaction from the transaction manager // this is the commit we will be checkpointing on - everything in this commit will be written to the file // any new commits made will be written to the next wal @@ -153,7 +224,7 @@ bool StorageManager::WALStartCheckpoint(MetaBlockPointer meta_block, CheckpointO } // verify the main WAL is the active WAL currently if (wal->GetPath() != wal_path) { - throw InternalException("Current WAL path %s does not match base WAL path %s in WALStartCheckpoint", + throw InternalException("Current WAL path \"%s\" does not match base WAL path \"%s\" in WALStartCheckpoint", wal->GetPath(), wal_path); } // write to the main WAL that we have initiated a checkpoint @@ -189,6 +260,7 @@ void StorageManager::WALFinishCheckpoint(lock_guard &) { // this is the common scenario if there are no concurrent writes happening while checkpointing // in this case we can just remove the main WAL and re-instantiate it to empty fs.TryRemoveFile(wal_path); + ResetWALEntriesCount(); wal = make_uniq(*this, wal_path); return; @@ -230,11 +302,11 @@ string StorageManager::GetWALPath(const string &suffix) { } string StorageManager::GetCheckpointWALPath() { - return GetWALPath(".checkpoint.wal"); + return GetWALPath(".wal.checkpoint"); } string StorageManager::GetRecoveryWALPath() { - return GetWALPath(".recovery.wal"); + return GetWALPath(".wal.recovery"); } bool StorageManager::InMemory() const { @@ -291,7 +363,7 @@ class SingleFileTableIOManager : public TableIOManager { } }; -SingleFileStorageManager::SingleFileStorageManager(AttachedDatabase &db, string path, const AttachOptions &options) +SingleFileStorageManager::SingleFileStorageManager(AttachedDatabase &db, string path, AttachOptions &options) : StorageManager(db, std::move(path), options) { } @@ -323,6 +395,7 @@ void SingleFileStorageManager::LoadDatabase(QueryContext context) { D_ASSERT(storage_options.block_header_size == DEFAULT_ENCRYPTION_BLOCK_HEADER_SIZE); options.encryption_options.encryption_enabled = true; options.encryption_options.user_key = std::move(storage_options.user_key); + options.encryption_options.encryption_version = storage_options.encryption_version; } idx_t row_group_size = DEFAULT_ROW_GROUP_SIZE; @@ -355,7 +428,7 @@ void SingleFileStorageManager::LoadDatabase(QueryContext context) { options.block_alloc_size = storage_options.block_alloc_size; } else { // No explicit option provided: use the default option. - options.block_alloc_size = config.options.default_block_alloc_size; + options.block_alloc_size = Settings::Get(config); } //! set the block header size for the encrypted database files //! set the database to encrypted @@ -560,10 +633,6 @@ void SingleFileStorageCommitState::AddRowGroupData(DataTable &table, idx_t start // cannot serialize optimistic block pointers if in-memory updates exist return; } - if (table.HasIndexes()) { - // cannot serialize optimistic block pointers if the table has indexes - return; - } auto &entries = optimistically_written_data[table]; auto entry = entries.find(start_index); if (entry != entries.end()) { @@ -639,8 +708,9 @@ void SingleFileStorageManager::CreateCheckpoint(QueryContext context, Checkpoint try { // Start timing the checkpoint. auto client_context = context.GetClientContext(); + ActiveTimer profiler; if (client_context) { - auto profiler = client_context->client_data->profiler->StartTimer(MetricType::CHECKPOINT_LATENCY); + profiler = client_context->client_data->profiler->StartTimer(MetricType::CHECKPOINT_LATENCY); } // Write the checkpoint. @@ -705,9 +775,22 @@ vector SingleFileStorageManager::GetMetadataInfo() { } bool SingleFileStorageManager::AutomaticCheckpoint(idx_t estimated_wal_bytes) { + auto &config = DBConfig::Get(db).options; + + // Check size-based threshold auto initial_size = NumericCast(GetWALSize()); idx_t expected_wal_size = initial_size + estimated_wal_bytes; - return expected_wal_size > DBConfig::Get(db).options.checkpoint_wal_size; + if (expected_wal_size > config.checkpoint_wal_size) { + return true; + } + + // Check entry-based threshold (if enabled) + auto entry_limit = Settings::Get(DBConfig::Get(db)); + if (entry_limit > 0 && GetWALEntriesCount() >= entry_limit) { + return true; + } + + return false; } shared_ptr SingleFileStorageManager::GetTableIOManager(BoundCreateTableInfo *info /*info*/) { diff --git a/src/duckdb/src/storage/table/array_column_data.cpp b/src/duckdb/src/storage/table/array_column_data.cpp index ad6618674..4fc2c0d4a 100644 --- a/src/duckdb/src/storage/table/array_column_data.cpp +++ b/src/duckdb/src/storage/table/array_column_data.cpp @@ -268,6 +268,14 @@ void ArrayColumnData::VisitBlockIds(BlockIdVisitor &visitor) const { child_column->VisitBlockIds(visitor); } +const BaseStatistics &ArrayColumnData::GetChildStats(const ColumnData &child) const { + if (!RefersToSameObject(child, *child_column)) { + throw InternalException("ArrayColumnData::GetChildStats provided column data is not a child of this array"); + } + auto &stats = GetStatisticsRef(); + return ArrayStats::GetChildStats(stats); +} + void ArrayColumnData::SetValidityData(shared_ptr validity_p) { if (validity) { throw InternalException("ArrayColumnData::SetValidityData cannot be used to overwrite existing validity"); @@ -333,11 +341,13 @@ unique_ptr ArrayColumnData::CreateCheckpointState(const R } unique_ptr ArrayColumnData::Checkpoint(const RowGroup &row_group, - ColumnCheckpointInfo &checkpoint_info) { + ColumnCheckpointInfo &checkpoint_info, + const BaseStatistics &old_stats) { auto &partial_block_manager = checkpoint_info.GetPartialBlockManager(); auto checkpoint_state = make_uniq(row_group, *this, partial_block_manager); - checkpoint_state->validity_state = validity->Checkpoint(row_group, checkpoint_info); - checkpoint_state->child_state = child_column->Checkpoint(row_group, checkpoint_info); + checkpoint_state->validity_state = validity->Checkpoint(row_group, checkpoint_info, old_stats); + checkpoint_state->child_state = + child_column->Checkpoint(row_group, checkpoint_info, ArrayStats::GetChildStats(old_stats)); return std::move(checkpoint_state); } diff --git a/src/duckdb/src/storage/table/column_data.cpp b/src/duckdb/src/storage/table/column_data.cpp index d3cb69da4..dfd251c8f 100644 --- a/src/duckdb/src/storage/table/column_data.cpp +++ b/src/duckdb/src/storage/table/column_data.cpp @@ -17,6 +17,7 @@ #include "duckdb/common/serializer/binary_deserializer.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/function/variant/variant_shredding.hpp" +#include "duckdb/storage/table/geo_column_data.hpp" namespace duckdb { @@ -416,12 +417,26 @@ FilterPropagateResult ColumnData::CheckZonemap(const StorageIndex &index, TableF lock_guard l(stats_lock); if (index.IsPushdownExtract()) { auto child_stats = stats->statistics.PushdownExtract(index.GetChildIndex(0)); - D_ASSERT(child_stats); + if (!child_stats) { + return FilterPropagateResult::NO_PRUNING_POSSIBLE; + } return filter.CheckStatistics(*child_stats); } return filter.CheckStatistics(stats->statistics); } +const BaseStatistics &ColumnData::GetStatisticsRef() const { + if (stats) { + return stats->statistics; + } + D_ASSERT(HasParent()); + return parent->GetChildStats(*this); +} + +const BaseStatistics &ColumnData::GetChildStats(const ColumnData &child) const { + throw InternalException("GetChildStats not implemented for ColumnData of type %s", type.ToString()); +} + unique_ptr ColumnData::GetStatistics() const { if (!stats) { throw InternalException("ColumnData::GetStatistics called on a column without stats"); @@ -609,7 +624,7 @@ void ColumnData::AppendTransientSegment(SegmentLock &l, idx_t start_row) { auto &config = DBConfig::GetConfig(db); auto function = config.GetCompressionFunction(CompressionType::COMPRESSION_UNCOMPRESSED, type.InternalType()); - auto new_segment = ColumnSegment::CreateTransientSegment(db, *function, type, segment_size, block_manager); + auto new_segment = ColumnSegment::CreateTransientSegment(db, function, type, segment_size, block_manager); AppendSegment(l, std::move(new_segment)); } @@ -665,6 +680,14 @@ void ColumnData::CheckpointScan(ColumnSegment &segment, ColumnScanState &state, unique_ptr ColumnData::Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &checkpoint_info) { + if (!stats) { + throw InternalException("ColumnData::Checkpoint called without stats on a nested column"); + } + return Checkpoint(row_group, checkpoint_info, this->stats->statistics); +} + +unique_ptr +ColumnData::Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &checkpoint_info, const BaseStatistics &stats) { // scan the segments of the column data // set up the checkpoint state auto &partial_block_manager = checkpoint_info.GetPartialBlockManager(); @@ -688,7 +711,7 @@ void ColumnData::InitializeColumn(PersistentColumnData &column_data) { } void ColumnData::InitializeColumn(PersistentColumnData &column_data, BaseStatistics &target_stats) { - D_ASSERT(type.InternalType() == column_data.physical_type); + D_ASSERT(type.InternalType() == column_data.logical_type.InternalType()); // construct the segments based on the data pointers this->count = 0; for (auto &data_pointer : column_data.pointers) { @@ -731,12 +754,11 @@ vector ColumnData::GetDataPointers() { return pointers; } -PersistentColumnData::PersistentColumnData(const LogicalType &logical_type) - : physical_type(logical_type.InternalType()), logical_type_id(logical_type.id()) { +PersistentColumnData::PersistentColumnData(const LogicalType &logical_type_p) : logical_type(logical_type_p) { } -PersistentColumnData::PersistentColumnData(const LogicalType &logical_type, vector pointers_p) - : physical_type(logical_type.InternalType()), logical_type_id(logical_type.id()), pointers(std::move(pointers_p)) { +PersistentColumnData::PersistentColumnData(const LogicalType &logical_type_p, vector pointers_p) + : logical_type(logical_type_p), pointers(std::move(pointers_p)) { D_ASSERT(!pointers.empty()); } @@ -747,35 +769,42 @@ void PersistentColumnData::Serialize(Serializer &serializer) const { if (has_updates) { throw InternalException("Column data with updates cannot be serialized"); } - serializer.WritePropertyWithDefault(100, "data_pointers", pointers); - if (child_columns.empty()) { - // validity column - D_ASSERT(physical_type == PhysicalType::BIT); - return; - } - serializer.WriteProperty(101, "validity", child_columns[0]); - - if (logical_type_id == LogicalTypeId::VARIANT) { - D_ASSERT(physical_type == PhysicalType::STRUCT); - D_ASSERT(child_columns.size() == 2 || child_columns.size() == 3); - auto unshredded_type = VariantShredding::GetUnshreddedType(); - serializer.WriteProperty(102, "unshredded", child_columns[1]); + // Serialize the extra data + serializer.WritePropertyWithDefault(99, "extra_data", extra_data); - if (child_columns.size() == 3) { - D_ASSERT(variant_shredded_type.id() == LogicalTypeId::STRUCT); - serializer.WriteProperty(115, "shredded_type", variant_shredded_type); - serializer.WriteProperty(120, "shredded", child_columns[2]); + // TODO: Dont special-case this + if (logical_type.id() == LogicalTypeId::VARIANT) { + serializer.WritePropertyWithDefault(100, "data_pointers", pointers); + serializer.WriteProperty(101, "validity", child_columns[0]); + serializer.WriteProperty(102, "unshredded", child_columns[1]); + if (child_columns.size() > 2) { + serializer.WriteProperty(103, "shredded", child_columns[2]); } return; } - if (physical_type == PhysicalType::ARRAY || physical_type == PhysicalType::LIST) { + switch (logical_type.InternalType()) { + case PhysicalType::BIT: { + serializer.WritePropertyWithDefault(100, "data_pointers", pointers); + } break; + case PhysicalType::ARRAY: + case PhysicalType::LIST: { D_ASSERT(child_columns.size() == 2); + serializer.WritePropertyWithDefault(100, "data_pointers", pointers); + serializer.WriteProperty(101, "validity", child_columns[0]); serializer.WriteProperty(102, "child_column", child_columns[1]); - } else if (physical_type == PhysicalType::STRUCT) { + } break; + case PhysicalType::STRUCT: { + serializer.WritePropertyWithDefault(100, "data_pointers", pointers); + serializer.WriteProperty(101, "validity", child_columns[0]); serializer.WriteList(102, "sub_columns", child_columns.size() - 1, [&](Serializer::List &list, idx_t i) { list.WriteElement(child_columns[i + 1]); }); + } break; + default: { + serializer.WritePropertyWithDefault(100, "data_pointers", pointers); + serializer.WriteProperty(101, "validity", child_columns[0]); + } break; } } @@ -786,53 +815,123 @@ void PersistentColumnData::DeserializeField(Deserializer &deserializer, field_id deserializer.Unset(); } -PersistentColumnData PersistentColumnData::Deserialize(Deserializer &deserializer) { - auto &type = deserializer.Get(); - auto physical_type = type.InternalType(); - PersistentColumnData result(type); - deserializer.ReadPropertyWithDefault(100, "data_pointers", static_cast &>(result.pointers)); - if (result.physical_type == PhysicalType::BIT) { - // validity: return +static PersistentColumnData GetPersistentColumnDataType(Deserializer &deserializer) { + auto extra_data = + deserializer.ReadPropertyWithExplicitDefault>(99, "extra_data", nullptr); + + if (!extra_data) { + // Get the type from the parent scope + auto &type = deserializer.Get(); + return PersistentColumnData(type); + } + + // Otherwise, the type of this segment may depend on extra data + switch (extra_data->GetType()) { + case ExtraPersistentColumnDataType::VARIANT: { + auto unshredded_type = VariantShredding::GetUnshreddedType(); + PersistentColumnData result(LogicalType::VARIANT()); + result.extra_data = std::move(extra_data); return result; } - result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); + case ExtraPersistentColumnDataType::GEOMETRY: { + const auto &geometry_data = extra_data->Cast(); + PersistentColumnData result(Geometry::GetVectorizedType(geometry_data.geom_type, geometry_data.vert_type)); + result.extra_data = std::move(extra_data); + return result; + } + default: + throw InternalException(""); + } +} +PersistentColumnData PersistentColumnData::Deserialize(Deserializer &deserializer) { + auto result = GetPersistentColumnDataType(deserializer); + const auto &type = result.logical_type; + + // TODO: Dont special-case this if (type.id() == LogicalTypeId::VARIANT) { - auto unshredded_type = VariantShredding::GetUnshreddedType(); + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); + result.DeserializeField(deserializer, 102, "unshredded", VariantShredding::GetUnshreddedType()); + if (result.extra_data) { + auto &variant_data = result.extra_data->Cast(); + result.DeserializeField(deserializer, 103, "shredded", variant_data.logical_type); + } + return result; + } + + // TODO: This is ugly + if (result.extra_data && result.extra_data->GetType() == ExtraPersistentColumnDataType::GEOMETRY) { + auto &geo_data = result.extra_data->Cast(); + auto actual_type = Geometry::GetVectorizedType(geo_data.geom_type, geo_data.vert_type); + + // We need to set the actual type in scope, as when we deserialize "data_pointers" we use it to detect + // the type of the statistics. + deserializer.Set(actual_type); + + switch (actual_type.InternalType()) { + case PhysicalType::BIT: { + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + } break; + case PhysicalType::ARRAY: { + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); + result.DeserializeField(deserializer, 102, "child_column", ArrayType::GetChildType(type)); + } break; + case PhysicalType::LIST: { + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); + result.DeserializeField(deserializer, 102, "child_column", ListType::GetChildType(type)); + } break; + case PhysicalType::STRUCT: { + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); + const auto &child_types = StructType::GetChildTypes(type); + deserializer.ReadList(102, "sub_columns", [&](Deserializer::List &list, idx_t i) { + deserializer.Set(child_types[i].second); + result.child_columns.push_back(list.ReadElement()); + deserializer.Unset(); + }); + } break; + default: { + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); + } break; + } - deserializer.Set(unshredded_type); - result.child_columns.push_back(deserializer.ReadProperty(102, "unshredded")); deserializer.Unset(); - auto shredded_type = - deserializer.ReadPropertyWithExplicitDefault(115, "shredded_type", LogicalType()); - if (shredded_type.id() == LogicalTypeId::STRUCT) { - deserializer.Set(shredded_type); - result.child_columns.push_back(deserializer.ReadProperty(120, "shredded")); - deserializer.Unset(); - result.SetVariantShreddedType(shredded_type); - } return result; } - switch (physical_type) { - case PhysicalType::ARRAY: + switch (type.InternalType()) { + case PhysicalType::BIT: { + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + } break; + case PhysicalType::ARRAY: { + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); result.DeserializeField(deserializer, 102, "child_column", ArrayType::GetChildType(type)); - break; - case PhysicalType::LIST: + } break; + case PhysicalType::LIST: { + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); result.DeserializeField(deserializer, 102, "child_column", ListType::GetChildType(type)); - break; + } break; case PhysicalType::STRUCT: { - auto &child_types = StructType::GetChildTypes(type); + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); + const auto &child_types = StructType::GetChildTypes(type); deserializer.ReadList(102, "sub_columns", [&](Deserializer::List &list, idx_t i) { deserializer.Set(child_types[i].second); result.child_columns.push_back(list.ReadElement()); deserializer.Unset(); }); - break; - } - default: - break; + } break; + default: { + deserializer.ReadPropertyWithDefault(100, "data_pointers", result.pointers); + result.DeserializeField(deserializer, 101, "validity", LogicalTypeId::VALIDITY); + } break; } return result; } @@ -849,12 +948,6 @@ bool PersistentColumnData::HasUpdates() const { return false; } -void PersistentColumnData::SetVariantShreddedType(const LogicalType &shredded_type) { - D_ASSERT(physical_type == PhysicalType::STRUCT); - D_ASSERT(logical_type_id == LogicalTypeId::VARIANT); - variant_shredded_type = shredded_type; -} - PersistentRowGroupData::PersistentRowGroupData(vector types_p) : types(std::move(types_p)) { } @@ -906,6 +999,42 @@ bool PersistentCollectionData::HasUpdates() const { return false; } +void ExtraPersistentColumnData::Serialize(Serializer &serializer) const { + serializer.WritePropertyWithDefault(100, "type", type, ExtraPersistentColumnDataType::INVALID); + switch (GetType()) { + case ExtraPersistentColumnDataType::VARIANT: { + const auto &variant_data = Cast(); + serializer.WriteProperty(101, "storage_type", variant_data.logical_type); + } break; + case ExtraPersistentColumnDataType::GEOMETRY: { + const auto &geometry_data = Cast(); + serializer.WritePropertyWithDefault(101, "geom_type", geometry_data.geom_type, GeometryType::INVALID); + serializer.WritePropertyWithDefault(102, "vert_type", geometry_data.vert_type, VertexType::XY); + } break; + default: + throw InternalException("Unknown PersistentColumnData type"); + } +} +unique_ptr ExtraPersistentColumnData::Deserialize(Deserializer &deserializer) { + auto type = deserializer.ReadPropertyWithExplicitDefault( + 100, "type", ExtraPersistentColumnDataType::INVALID); + switch (type) { + case ExtraPersistentColumnDataType::VARIANT: { + auto storage_type = + deserializer.ReadPropertyWithExplicitDefault(101, "storage_type", LogicalType()); + return make_uniq(storage_type); + } + case ExtraPersistentColumnDataType::GEOMETRY: { + auto geom_type = + deserializer.ReadPropertyWithExplicitDefault(101, "geom_type", GeometryType::INVALID); + auto vert_type = deserializer.ReadPropertyWithExplicitDefault(102, "vert_type", VertexType::XY); + return make_uniq(geom_type, vert_type); + } + default: + throw InternalException("Unknown PersistentColumnData type"); + } +} + PersistentColumnData ColumnData::Serialize() { auto result = count ? PersistentColumnData(type, GetDataPointers()) : PersistentColumnData(type); result.has_updates = HasUpdates(); @@ -1017,11 +1146,20 @@ void ColumnData::GetColumnSegmentInfo(const QueryContext &context, idx_t row_gro void ColumnData::Verify(RowGroup &parent) { #ifdef DEBUG data.Verify(); - if (type.InternalType() == PhysicalType::STRUCT || type.InternalType() == PhysicalType::ARRAY) { + + bool is_geometry_child_column = false; + if (type.id() == LogicalTypeId::GEOMETRY && this->parent && this->parent->type.id() == LogicalTypeId::GEOMETRY) { + // Geometry child column + is_geometry_child_column = true; + } + + if (type.InternalType() == PhysicalType::STRUCT || type.InternalType() == PhysicalType::ARRAY || + (type.id() == LogicalTypeId::GEOMETRY && !is_geometry_child_column)) { // structs and fixed size lists don't have segments D_ASSERT(!data.GetRootSegment()); return; } + idx_t current_index = 0; idx_t current_start = 0; idx_t total_count = 0; @@ -1039,16 +1177,22 @@ void ColumnData::Verify(RowGroup &parent) { shared_ptr ColumnData::CreateColumn(BlockManager &block_manager, DataTableInfo &info, idx_t column_index, const LogicalType &type, ColumnDataType data_type, optional_ptr parent) { + if (type.id() == LogicalTypeId::GEOMETRY) { + return make_shared_ptr(block_manager, info, column_index, type, data_type, parent); + } if (type.id() == LogicalTypeId::VARIANT) { return make_shared_ptr(block_manager, info, column_index, type, data_type, parent); } if (type.InternalType() == PhysicalType::STRUCT) { return make_shared_ptr(block_manager, info, column_index, type, data_type, parent); - } else if (type.InternalType() == PhysicalType::LIST) { + } + if (type.InternalType() == PhysicalType::LIST) { return make_shared_ptr(block_manager, info, column_index, type, data_type, parent); - } else if (type.InternalType() == PhysicalType::ARRAY) { + } + if (type.InternalType() == PhysicalType::ARRAY) { return make_shared_ptr(block_manager, info, column_index, type, data_type, parent); - } else if (type.id() == LogicalTypeId::VALIDITY) { + } + if (type.id() == LogicalTypeId::VALIDITY) { return make_shared_ptr(block_manager, info, column_index, data_type, parent); } return make_shared_ptr(block_manager, info, column_index, type, data_type, parent); diff --git a/src/duckdb/src/storage/table/column_data_checkpointer.cpp b/src/duckdb/src/storage/table/column_data_checkpointer.cpp index 281457cbf..cc374aeca 100644 --- a/src/duckdb/src/storage/table/column_data_checkpointer.cpp +++ b/src/duckdb/src/storage/table/column_data_checkpointer.cpp @@ -1,5 +1,7 @@ #include "duckdb/storage/table/column_data_checkpointer.hpp" + #include "duckdb/main/config.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/storage/table/update_segment.hpp" #include "duckdb/storage/data_table.hpp" #include "duckdb/parser/column_definition.hpp" @@ -15,7 +17,7 @@ CompressionFunction &ColumnDataCheckpointData::GetCompressionFunction(Compressio auto &db = col_data->GetDatabase(); auto &column_type = col_data->type; auto &config = DBConfig::GetConfig(db); - return *config.GetCompressionFunction(compression_type, column_type.InternalType()); + return config.GetCompressionFunction(compression_type, column_type.InternalType()); } DatabaseInstance &ColumnDataCheckpointData::GetDatabase() { @@ -168,9 +170,11 @@ vector ColumnDataCheckpointer::DetectBestCompressionMet if (compression_type != CompressionType::COMPRESSION_AUTO) { forced_methods[i] = ForceCompression(storage_manager, functions, compression_type); } - if (compression_type == CompressionType::COMPRESSION_AUTO && - config.options.force_compression != CompressionType::COMPRESSION_AUTO) { - forced_methods[i] = ForceCompression(storage_manager, functions, config.options.force_compression); + if (compression_type == CompressionType::COMPRESSION_AUTO) { + auto force_compression = Settings::Get(config); + if (force_compression != CompressionType::COMPRESSION_AUTO) { + forced_methods[i] = ForceCompression(storage_manager, functions, force_compression); + } } } @@ -303,7 +307,7 @@ void ColumnDataCheckpointer::WriteToDisk() { // Analyze the candidate functions auto &config = DBConfig::GetConfig(db); // Override the function to the COMPRESSION_EMPTY // turning the compression+final compress steps into a no-op, saving a single empty segment - validity.function = config.GetCompressionFunction(CompressionType::COMPRESSION_EMPTY, PhysicalType::BIT); + validity.function = config.GetCompressionFunction(CompressionType::COMPRESSION_EMPTY, PhysicalType::BIT).get(); } // Initialize the compression for the selected function diff --git a/src/duckdb/src/storage/table/column_segment.cpp b/src/duckdb/src/storage/table/column_segment.cpp index 8589c5e64..1d45b8f1c 100644 --- a/src/duckdb/src/storage/table/column_segment.cpp +++ b/src/duckdb/src/storage/table/column_segment.cpp @@ -29,16 +29,15 @@ unique_ptr ColumnSegment::CreatePersistentSegment(DatabaseInstanc BaseStatistics statistics, unique_ptr segment_state) { auto &config = DBConfig::GetConfig(db); - optional_ptr function; shared_ptr block; - function = config.GetCompressionFunction(compression_type, type.InternalType()); + auto function = config.GetCompressionFunction(compression_type, type.InternalType()); if (block_id != INVALID_BLOCK) { block = block_manager.RegisterBlock(block_id); } auto segment_size = block_manager.GetBlockSize(); - return make_uniq(db, std::move(block), type, ColumnSegmentType::PERSISTENT, count, *function, + return make_uniq(db, std::move(block), type, ColumnSegmentType::PERSISTENT, count, function, std::move(statistics), block_id, offset, segment_size, std::move(segment_state)); } @@ -70,7 +69,7 @@ ColumnSegment::ColumnSegment(DatabaseInstance &db, shared_ptr block } // For constant segments (CompressionType::COMPRESSION_CONSTANT) the block is a nullptr. - D_ASSERT(!block || segment_size <= GetBlockManager().GetBlockSize()); + D_ASSERT(!block || segment_size <= GetBlockSize()); } ColumnSegment::ColumnSegment(ColumnSegment &other) @@ -79,7 +78,7 @@ ColumnSegment::ColumnSegment(ColumnSegment &other) block(std::move(other.block)), function(other.function), block_id(other.block_id), offset(other.offset), segment_size(other.segment_size), segment_state(std::move(other.segment_state)) { // For constant segments (CompressionType::COMPRESSION_CONSTANT) the block is a nullptr. - D_ASSERT(!block || segment_size <= GetBlockManager().GetBlockSize()); + D_ASSERT(!block || segment_size <= GetBlockSize()); } ColumnSegment::~ColumnSegment() { @@ -165,7 +164,7 @@ idx_t ColumnSegment::SegmentSize() const { void ColumnSegment::Resize(idx_t new_size) { D_ASSERT(new_size > segment_size); D_ASSERT(offset == 0); - D_ASSERT(block && new_size <= GetBlockManager().GetBlockSize()); + D_ASSERT(block && new_size <= GetBlockSize()); auto &buffer_manager = BufferManager::GetBufferManager(db); auto old_handle = buffer_manager.Pin(block); @@ -236,7 +235,7 @@ void ColumnSegment::ConvertToPersistent(QueryContext context, optional_ptr parent) + : ColumnData(block_manager, info, column_index, std::move(type_p), data_type, parent) { + if (data_type != ColumnDataType::CHECKPOINT_TARGET) { + base_column = make_shared_ptr(block_manager, info, column_index, type, data_type, this); + } +} + +//---------------------------------------------------------------------------------------------------------------------- +// Scan +//---------------------------------------------------------------------------------------------------------------------- + +void GeoColumnData::InitializePrefetch(PrefetchState &prefetch_state, ColumnScanState &scan_state, idx_t rows) { + return base_column->InitializePrefetch(prefetch_state, scan_state, rows); +} + +void GeoColumnData::InitializeChildScanStates(ColumnScanState &state) { + // Reset, inner layout might be different + state.child_states.clear(); + + // Initialize using the type of the base column + state.Initialize(state.context, base_column->type, state.scan_options); +} + +void GeoColumnData::InitializeScan(ColumnScanState &state) { + InitializeChildScanStates(state); + return base_column->InitializeScan(state); +} + +void GeoColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) { + InitializeChildScanStates(state); + return base_column->InitializeScanWithOffset(state, row_idx); +} + +idx_t GeoColumnData::Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, + idx_t target_count) { + auto &layout_type = base_column->GetType(); + + // Not a shredded column, so just emit the binary format immediately + if (layout_type.id() == LogicalTypeId::GEOMETRY) { + return base_column->Scan(transaction, vector_index, state, result, target_count); + } + + // Setup an intermediate chunk to scan the actual data, based on how much we actually scanned + // TODO: Put this in a scan state? + DataChunk scan_chunk; + scan_chunk.Initialize(Allocator::DefaultAllocator(), {layout_type}, target_count); + + const auto scan_count = base_column->Scan(transaction, vector_index, state, scan_chunk.data[0], target_count); + + // Now reassemble + Reassemble(scan_chunk.data[0], result, scan_count, geom_type, vert_type, 0); + return scan_count; +} + +idx_t GeoColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t target_count, idx_t result_offset) { + auto &layout_type = base_column->GetType(); + + // Not a shredded column, so just emit the binary format immediately + if (layout_type.id() == LogicalTypeId::GEOMETRY) { + return base_column->ScanCount(state, result, target_count, result_offset); + } + + // Setup an intermediate chunk to scan the actual data, based on how much we actually scanned + // TODO: Put this in a scan state + DataChunk scan_chunk; + scan_chunk.Initialize(Allocator::DefaultAllocator(), {layout_type}, target_count); + + const auto scan_count = base_column->ScanCount(state, scan_chunk.data[0], target_count, 0); + + // Now reassemble + Reassemble(scan_chunk.data[0], result, scan_count, geom_type, vert_type, result_offset); + return scan_count; +} + +void GeoColumnData::Skip(ColumnScanState &state, idx_t count) { + return base_column->Skip(state, count); +} + +//---------------------------------------------------------------------------------------------------------------------- +// Append +//---------------------------------------------------------------------------------------------------------------------- + +void GeoColumnData::InitializeAppend(ColumnAppendState &state) { + base_column->InitializeAppend(state); +} +void GeoColumnData::Append(BaseStatistics &stats, ColumnAppendState &state, Vector &vector, idx_t add_count) { + base_column->Append(stats, state, vector, add_count); + count += add_count; +} +void GeoColumnData::RevertAppend(row_t new_count) { + base_column->RevertAppend(new_count); + count = UnsafeNumericCast(new_count); +} + +//---------------------------------------------------------------------------------------------------------------------- +// Fetch +//---------------------------------------------------------------------------------------------------------------------- + +idx_t GeoColumnData::Fetch(ColumnScanState &state, row_t row_id, Vector &result) { + auto &layout_type = base_column->GetType(); + + // Not a shredded column, so just emit the binary format immediately + if (layout_type.id() == LogicalTypeId::GEOMETRY) { + return base_column->Fetch(state, row_id, result); + } + + // Otherwise, we need to fetch and reassemble + DataChunk chunk; + chunk.Initialize(Allocator::DefaultAllocator(), {layout_type}, 1); + + const auto fetch_count = base_column->Fetch(state, row_id, chunk.data[0]); + + Reassemble(chunk.data[0], result, fetch_count, geom_type, vert_type, 0); + + return fetch_count; +} + +void GeoColumnData::FetchRow(TransactionData transaction, ColumnFetchState &state, const StorageIndex &storage_index, + row_t row_id, Vector &result, idx_t result_idx) { + auto &layout_type = base_column->GetType(); + + // Not a shredded column, so just emit the binary format immediately + if (layout_type.id() == LogicalTypeId::GEOMETRY) { + return base_column->FetchRow(transaction, state, storage_index, row_id, result, result_idx); + } + + // Otherwise, we need to fetch and reassemble + DataChunk chunk; + chunk.Initialize(Allocator::DefaultAllocator(), {layout_type}, 1); + + base_column->FetchRow(transaction, state, storage_index, row_id, chunk.data[0], 0); + + Reassemble(chunk.data[0], result, 1, geom_type, vert_type, result_idx); +} + +//---------------------------------------------------------------------------------------------------------------------- +// Update +//---------------------------------------------------------------------------------------------------------------------- + +void GeoColumnData::Update(TransactionData transaction, DataTable &data_table, idx_t column_index, + Vector &update_vector, row_t *row_ids, idx_t update_count, idx_t row_group_start) { + return base_column->Update(transaction, data_table, column_index, update_vector, row_ids, update_count, + row_group_start); +} +void GeoColumnData::UpdateColumn(TransactionData transaction, DataTable &data_table, + const vector &column_path, Vector &update_vector, row_t *row_ids, + idx_t update_count, idx_t depth, idx_t row_group_start) { + return base_column->UpdateColumn(transaction, data_table, column_path, update_vector, row_ids, update_count, depth, + row_group_start); +} + +unique_ptr GeoColumnData::GetUpdateStatistics() { + return base_column->GetUpdateStatistics(); +} + +//---------------------------------------------------------------------------------------------------------------------- +// Checkpoint +//---------------------------------------------------------------------------------------------------------------------- + +class GeoColumnCheckpointState final : public ColumnCheckpointState { +public: + GeoColumnCheckpointState(const RowGroup &row_group, ColumnData &column_data, + PartialBlockManager &partial_block_manager) + : ColumnCheckpointState(row_group, column_data, partial_block_manager) { + // Make stats + global_stats = GeometryStats::CreateEmpty(column_data.type).ToUnique(); + + // Also pass on the shredding state + const auto &geo_column = column_data.Cast(); + geom_type = geo_column.geom_type; + vert_type = geo_column.vert_type; + } + + // Shared pointer to the new/old inner column. + // This is never actually used here, but needs to stay alive + // for as long as the checkpoint state, hence the shared_ptr. + shared_ptr inner_column; + + // The checkpoint state for the inner column. + unique_ptr inner_column_state; + + GeometryType geom_type = GeometryType::INVALID; + VertexType vert_type = VertexType::XY; + + shared_ptr CreateEmptyColumnData() override { + auto new_column = make_shared_ptr( + original_column.GetBlockManager(), original_column.GetTableInfo(), original_column.column_index, + original_column.type, ColumnDataType::CHECKPOINT_TARGET, nullptr); + return std::move(new_column); + } + + shared_ptr GetFinalResult() override { + if (!result_column) { + result_column = CreateEmptyColumnData(); + } + + auto &column_data = result_column->Cast(); + + auto new_inner = inner_column_state->GetFinalResult(); + new_inner->SetParent(column_data); + column_data.base_column = std::move(new_inner); + + // Pass on the shredding state too + column_data.geom_type = geom_type; + column_data.vert_type = vert_type; + + return ColumnCheckpointState::GetFinalResult(); + } + + unique_ptr GetStatistics() override { + D_ASSERT(global_stats); + return std::move(global_stats); + } + + PersistentColumnData ToPersistentData() override { + auto inner_data = inner_column_state->ToPersistentData(); + + // If this is a shredded column, record it in the persistent data! + if (geom_type != GeometryType::INVALID) { + auto extra_data = make_uniq(); + extra_data->geom_type = geom_type; + extra_data->vert_type = vert_type; + inner_data.extra_data = std::move(extra_data); + } + + return inner_data; + } +}; + +unique_ptr GeoColumnData::CreateCheckpointState(const RowGroup &row_group, + PartialBlockManager &partial_block_manager) { + return make_uniq(row_group, *this, partial_block_manager); +} + +unique_ptr GeoColumnData::Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &old_stats) { + auto &partial_block_manager = info.GetPartialBlockManager(); + auto checkpoint_state = make_uniq(row_group, *this, partial_block_manager); + + auto &old_column_stats = + base_column->GetType().id() == LogicalTypeId::GEOMETRY ? old_stats : base_column->GetStatisticsRef(); + + // Are there any changes? + if (!HasAnyChanges()) { + // No changes, keep column + checkpoint_state->inner_column = base_column; + checkpoint_state->inner_column_state = + checkpoint_state->inner_column->Checkpoint(row_group, info, old_column_stats); + return std::move(checkpoint_state); + } + + // Do we have enough rows to consider shredding? + auto &table_info = row_group.GetTableInfo(); + auto &db = table_info.GetDB(); + + const auto shredding_threshold = Settings::Get(DBConfig::Get(db)); + const auto current_row_count = count.load(); + + auto should_shred = shredding_threshold >= 0 && current_row_count >= static_cast(shredding_threshold); + if (!should_shred) { + // Keep column + checkpoint_state->inner_column = base_column; + checkpoint_state->inner_column_state = + checkpoint_state->inner_column->Checkpoint(row_group, info, old_column_stats); + checkpoint_state->global_stats = checkpoint_state->inner_column_state->GetStatistics(); + return std::move(checkpoint_state); + } + + // Figure out if this segment can use an alternative type layout + auto new_geom_type = GeometryType::POINT; + auto new_vert_type = VertexType::XY; + + const auto &types = GeometryStats::GetTypes(old_stats); + const auto &flags = GeometryStats::GetFlags(old_stats); + + auto has_mixed_type = !types.TryGetSingleType(new_geom_type, new_vert_type); + auto has_only_geometry_collection = new_geom_type == GeometryType::GEOMETRYCOLLECTION; + auto has_only_invalid = new_geom_type == GeometryType::INVALID; + + // We cant specialize empty geometries, because we cant represent zero-vertex geometries in those layouts + const auto has_empty = flags.HasEmptyGeometry() || flags.HasEmptyPart(); + + if (has_mixed_type || has_only_geometry_collection || has_only_invalid || has_empty) { + // Cant specialize, keep column + checkpoint_state->inner_column = base_column; + checkpoint_state->inner_column_state = + checkpoint_state->inner_column->Checkpoint(row_group, info, old_column_stats); + checkpoint_state->global_stats = checkpoint_state->inner_column_state->GetStatistics(); + return std::move(checkpoint_state); + } + + auto new_type = Geometry::GetVectorizedType(new_geom_type, new_vert_type); + + auto new_column = CreateColumn(block_manager, this->info, base_column->column_index, new_type, GetDataType(), this); + + // Setup scan from the old column + DataChunk scan_chunk; + ColumnScanState scan_state(nullptr); + scan_chunk.Initialize(Allocator::DefaultAllocator(), {base_column->type}, STANDARD_VECTOR_SIZE); + InitializeScan(scan_state); + + // Setup append to the new column + DataChunk append_chunk; + ColumnAppendState append_state; + append_chunk.Initialize(Allocator::DefaultAllocator(), {new_column->type}, STANDARD_VECTOR_SIZE); + new_column->InitializeAppend(append_state); + + idx_t total_count = count.load(); + idx_t vector_index = 0; + + for (idx_t scanned = 0; scanned < total_count; scanned += STANDARD_VECTOR_SIZE) { + scan_chunk.Reset(); + + auto to_scan = MinValue(total_count - scanned, static_cast(STANDARD_VECTOR_SIZE)); + Scan(TransactionData::Committed(), vector_index++, scan_state, scan_chunk.data[0], to_scan); + + // Verify the scan chunk + scan_chunk.Verify(); + + append_chunk.Reset(); + append_chunk.SetCardinality(to_scan); + + // Make the split + Specialize(scan_chunk.data[0], append_chunk.data[0], to_scan, new_geom_type, new_vert_type); + + // Append into the new specialized column + auto dummy_stats = BaseStatistics::CreateEmpty(new_column->GetType()); + new_column->Append(dummy_stats, append_state, append_chunk.data[0], to_scan); + + // Merge the stats into the checkpoint state's global stats + InterpretStats(dummy_stats, *checkpoint_state->global_stats, new_geom_type, new_vert_type); + } + + // Move then new column into our checkpoint state + auto empty_stats = BaseStatistics::CreateEmpty(new_column->GetType()); + checkpoint_state->inner_column = new_column; + checkpoint_state->inner_column_state = checkpoint_state->inner_column->Checkpoint(row_group, info, empty_stats); + + // Also set the shredding state + checkpoint_state->geom_type = new_geom_type; + checkpoint_state->vert_type = new_vert_type; + + return std::move(checkpoint_state); +} + +bool GeoColumnData::IsPersistent() { + return base_column->IsPersistent(); +} + +bool GeoColumnData::HasAnyChanges() const { + return base_column->HasAnyChanges(); +} + +PersistentColumnData GeoColumnData::Serialize() { + // Serialize the inner column + auto inner_data = base_column->Serialize(); + + // If this is a shredded column, record it in the persistent data! + if (geom_type != GeometryType::INVALID) { + auto extra_data = make_uniq(); + extra_data->geom_type = geom_type; + extra_data->vert_type = vert_type; + inner_data.extra_data = std::move(extra_data); + } + + return inner_data; +} + +void GeoColumnData::InitializeColumn(PersistentColumnData &column_data, BaseStatistics &target_stats) { + if (!column_data.extra_data) { + // No shredding, just initialize normally + base_column->InitializeColumn(column_data, target_stats); + count = base_column->count.load(); + return; + } + + auto &geom_data = column_data.extra_data->Cast(); + + // Set the shredding state + vert_type = geom_data.vert_type; + geom_type = geom_data.geom_type; + + // Else, this is a shredded point + const auto layout_type = Geometry::GetVectorizedType(geom_type, vert_type); + base_column = CreateColumn(block_manager, info, base_column->column_index, layout_type, GetDataType(), this); + D_ASSERT(base_column != nullptr); + + auto dummy_stats = BaseStatistics::CreateEmpty(layout_type); + base_column->InitializeColumn(column_data, dummy_stats); + count = base_column->count.load(); + + // Interpret the stats + InterpretStats(dummy_stats, target_stats, geom_type, vert_type); +} + +//---------------------------------------------------------------------------------------------------------------------- +// Misc +//---------------------------------------------------------------------------------------------------------------------- + +idx_t GeoColumnData::GetMaxEntry() { + return base_column->GetMaxEntry(); +} + +void GeoColumnData::GetColumnSegmentInfo(const QueryContext &context, idx_t row_group_index, vector col_path, + vector &result) { + return base_column->GetColumnSegmentInfo(context, row_group_index, col_path, result); +} + +void GeoColumnData::Verify(RowGroup &parent) { + return base_column->Verify(parent); +} + +void GeoColumnData::VisitBlockIds(BlockIdVisitor &visitor) const { + return base_column->VisitBlockIds(visitor); +} + +//---------------------------------------------------------------------------------------------------------------------- +// Specialize +//---------------------------------------------------------------------------------------------------------------------- +void GeoColumnData::Specialize(Vector &source, Vector &target, idx_t count, GeometryType geom_type, + VertexType vert_type) { + Geometry::ToVectorizedFormat(source, target, count, geom_type, vert_type); +} + +void GeoColumnData::Reassemble(Vector &source, Vector &target, idx_t count, GeometryType geom_type, + VertexType vert_type, idx_t result_offset) { + Geometry::FromVectorizedFormat(source, target, count, geom_type, vert_type, result_offset); +} + +static const BaseStatistics *GetVertexStats(BaseStatistics &stats, GeometryType geom_type) { + switch (geom_type) { + case GeometryType::POINT: { + return StructStats::GetChildStats(stats); + } + case GeometryType::LINESTRING: { + const auto &line_stats = ListStats::GetChildStats(stats); + return StructStats::GetChildStats(line_stats); + } + case GeometryType::POLYGON: { + const auto &poly_stats = ListStats::GetChildStats(stats); + const auto &ring_stats = ListStats::GetChildStats(poly_stats); + return StructStats::GetChildStats(ring_stats); + } + case GeometryType::MULTIPOINT: { + const auto &mpoint_stats = ListStats::GetChildStats(stats); + return StructStats::GetChildStats(mpoint_stats); + } + case GeometryType::MULTILINESTRING: { + const auto &mline_stats = ListStats::GetChildStats(stats); + const auto &line_stats = ListStats::GetChildStats(mline_stats); + return StructStats::GetChildStats(line_stats); + } + case GeometryType::MULTIPOLYGON: { + const auto &mpoly_stats = ListStats::GetChildStats(stats); + const auto &poly_stats = ListStats::GetChildStats(mpoly_stats); + const auto &ring_stats = ListStats::GetChildStats(poly_stats); + return StructStats::GetChildStats(ring_stats); + } + default: + throw NotImplementedException("Unsupported geometry type %d for interpreting stats", + static_cast(geom_type)); + } +} + +void GeoColumnData::InterpretStats(BaseStatistics &source, BaseStatistics &target, GeometryType geom_type, + VertexType vert_type) { + // Copy base stats + target.CopyBase(source); + + // Extract vertex stats + const auto vert_stats = GetVertexStats(source, geom_type); + auto &extent = GeometryStats::GetExtent(target); + extent.x_min = NumericStats::GetMin(vert_stats[0]); + extent.x_max = NumericStats::GetMax(vert_stats[0]); + extent.y_min = NumericStats::GetMin(vert_stats[1]); + extent.y_max = NumericStats::GetMax(vert_stats[1]); + + switch (vert_type) { + case VertexType::XYZ: + extent.z_min = NumericStats::GetMin(vert_stats[2]); + extent.z_max = NumericStats::GetMax(vert_stats[2]); + break; + case VertexType::XYM: + extent.m_min = NumericStats::GetMin(vert_stats[2]); + extent.m_max = NumericStats::GetMax(vert_stats[2]); + break; + case VertexType::XYZM: + extent.z_min = NumericStats::GetMin(vert_stats[2]); + extent.z_max = NumericStats::GetMax(vert_stats[2]); + extent.m_min = NumericStats::GetMin(vert_stats[3]); + extent.m_max = NumericStats::GetMax(vert_stats[3]); + break; + default: + // Nothing to do + break; + } + + // Set types + auto &types = GeometryStats::GetTypes(target); + types.Clear(); + types.Add(geom_type, vert_type); + + // Also set non-empty flag + auto &geo_flags = GeometryStats::GetFlags(target); + geo_flags.Clear(); + geo_flags.SetHasNonEmptyGeometry(); + geo_flags.SetHasNonEmptyPart(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/storage/table/list_column_data.cpp b/src/duckdb/src/storage/table/list_column_data.cpp index cbf65a0f4..13b0fa691 100644 --- a/src/duckdb/src/storage/table/list_column_data.cpp +++ b/src/duckdb/src/storage/table/list_column_data.cpp @@ -326,6 +326,14 @@ void ListColumnData::VisitBlockIds(BlockIdVisitor &visitor) const { child_column->VisitBlockIds(visitor); } +const BaseStatistics &ListColumnData::GetChildStats(const ColumnData &child) const { + if (!RefersToSameObject(child, *child_column)) { + throw InternalException("ListColumnData::GetChildStats provided column data is not a child of this list"); + } + auto &stats = GetStatisticsRef(); + return ListStats::GetChildStats(stats); +} + void ListColumnData::SetValidityData(shared_ptr validity_p) { if (validity) { throw InternalException("ListColumnData::SetValidityData cannot be used to overwrite existing validity"); @@ -390,10 +398,11 @@ unique_ptr ListColumnData::CreateCheckpointState(const Ro } unique_ptr ListColumnData::Checkpoint(const RowGroup &row_group, - ColumnCheckpointInfo &checkpoint_info) { - auto base_state = ColumnData::Checkpoint(row_group, checkpoint_info); - auto validity_state = validity->Checkpoint(row_group, checkpoint_info); - auto child_state = child_column->Checkpoint(row_group, checkpoint_info); + ColumnCheckpointInfo &checkpoint_info, + const BaseStatistics &old_stats) { + auto base_state = ColumnData::Checkpoint(row_group, checkpoint_info, old_stats); + auto validity_state = validity->Checkpoint(row_group, checkpoint_info, old_stats); + auto child_state = child_column->Checkpoint(row_group, checkpoint_info, ListStats::GetChildStats(old_stats)); auto &checkpoint_state = base_state->Cast(); checkpoint_state.validity_state = std::move(validity_state); diff --git a/src/duckdb/src/storage/table/row_group.cpp b/src/duckdb/src/storage/table/row_group.cpp index b0650b994..b57a74906 100644 --- a/src/duckdb/src/storage/table/row_group.cpp +++ b/src/duckdb/src/storage/table/row_group.cpp @@ -187,16 +187,18 @@ void RowGroup::InitializeEmpty(const vector &types, ColumnDataType } } -static unique_ptr CreateCast(ClientContext &context, const LogicalType &original_type, - const LogicalType &cast_type) { - auto input = make_uniq(original_type, 0U); - auto cast_expression = BoundCastExpression::AddCastToType(context, std::move(input), cast_type); - auto res = make_uniq(context); - res->target.Initialize(context, {cast_type}); - res->input.Initialize(context, {original_type}); - res->executor.AddExpression(*cast_expression); - res->expression = std::move(cast_expression); - return res; +void ColumnScanState::PushDownCast(const LogicalType &original_type, const LogicalType &cast_type) { + D_ASSERT(context.Valid()); + D_ASSERT(!expression_state); + auto &client_context = *context.GetClientContext(); + + auto input = make_uniq(original_type, 0ULL); + auto cast_expression = BoundCastExpression::AddCastToType(client_context, std::move(input), cast_type); + expression_state = make_uniq(client_context); + expression_state->target.Initialize(client_context, {cast_type}); + expression_state->input.Initialize(client_context, {original_type}); + expression_state->executor.AddExpression(*cast_expression); + expression_state->expression = std::move(cast_expression); } void ColumnScanState::Initialize(const QueryContext &context_p, const LogicalType &type, const StorageIndex &column_id, @@ -217,6 +219,13 @@ void ColumnScanState::Initialize(const QueryContext &context_p, const LogicalTyp // variant - column scan states are created later // this is done because the internal shape of the VARIANT is different per rowgroup scan_child_column.resize(2, true); + if (!storage_index.IsPushdownExtract()) { + return; + } + auto &scan_type = storage_index.GetScanType(); + if (scan_type.id() != LogicalTypeId::VARIANT) { + PushDownCast(type, scan_type); + } return; } @@ -244,7 +253,7 @@ void ColumnScanState::Initialize(const QueryContext &context_p, const LogicalTyp auto child_index = child.GetPrimaryIndex(); auto &child_type = StructType::GetChildTypes(type)[child_index].second; if (!child.HasChildren() && child_type != child.GetType()) { - expression_state = CreateCast(*context.GetClientContext(), child_type, child.GetType()); + PushDownCast(child_type, child.GetType()); } child_states[1].Initialize(context, struct_children[child_index].second, child, options); } else { @@ -1178,7 +1187,7 @@ const vector &RowGroup::GetColumnStartPointers() const { } RowGroupWriteData RowGroup::WriteToDisk(RowGroupWriter &writer) { - if (DBConfig::GetSetting(writer.GetDatabase()) && !column_pointers.empty() && + if (Settings::Get(writer.GetDatabase()) && !column_pointers.empty() && !HasChanges()) { // we have existing metadata and the row group has not been changed // re-use previous metadata diff --git a/src/duckdb/src/storage/table/row_group_collection.cpp b/src/duckdb/src/storage/table/row_group_collection.cpp index 66f6d3fec..703320b34 100644 --- a/src/duckdb/src/storage/table/row_group_collection.cpp +++ b/src/duckdb/src/storage/table/row_group_collection.cpp @@ -74,6 +74,11 @@ idx_t RowGroupCollection::GetTotalRows() const { return total_rows.load(); } +idx_t RowGroupCollection::GetRowGroupCount() const { + auto row_groups = GetRowGroups(); + return row_groups->GetSegmentCount(); +} + const vector &RowGroupCollection::GetTypes() const { return types; } @@ -227,7 +232,7 @@ void RowGroupCollection::InitializeScanWithOffset(const QueryContext &context, C } } -bool RowGroupCollection::InitializeScanInRowGroup(const QueryContext &context, CollectionScanState &state, +bool RowGroupCollection::InitializeScanInRowGroup(ClientContext &context, CollectionScanState &state, RowGroupCollection &collection, SegmentNode &row_group, idx_t vector_index, idx_t max_row) { state.max_row = max_row; @@ -307,39 +312,86 @@ bool RowGroupCollection::NextParallelScan(ClientContext &context, ParallelCollec return false; } -bool RowGroupCollection::Scan(DuckTransaction &transaction, const vector &column_ids, - const std::function &fun) { - vector scan_types; - for (idx_t i = 0; i < column_ids.size(); i++) { - scan_types.push_back(types[column_ids[i].GetPrimaryIndex()]); - } - DataChunk chunk; - chunk.Initialize(GetAllocator(), scan_types); +//===--------------------------------------------------------------------===// +// Iterator +//===--------------------------------------------------------------------===// +RowGroupIterationHelper::RowGroupIterationHelper(RowGroupCollection &collection, DuckTransaction &transaction, + vector column_ids_p) + : collection(collection), transaction(transaction), column_ids(std::move(column_ids_p)) { +} - // initialize the scan - TableScanState state; - state.Initialize(column_ids, nullptr); - InitializeScan(QueryContext(), state.local_state, column_ids, nullptr); +RowGroupIterationHelper::RowGroupIterator RowGroupIterationHelper::begin() { // NOLINT: match stl API + return RowGroupIterator(collection, &transaction, column_ids); +} +RowGroupIterationHelper::RowGroupIterator RowGroupIterationHelper::end() { // NOLINT: match stl API + return RowGroupIterator(nullptr, nullptr, column_ids); +} - while (true) { - chunk.Reset(); - state.local_state.Scan(transaction, chunk); - if (chunk.size() == 0) { - return true; - } - if (!fun(chunk)) { - return false; +RowGroupIterationHelper::RowGroupIterator::RowGroupIterator(optional_ptr collection, + optional_ptr transaction, + const vector &column_ids) + : collection(collection), transaction(transaction) { + if (collection) { + vector scan_types; + auto &types = collection->GetTypes(); + for (idx_t i = 0; i < column_ids.size(); i++) { + scan_types.push_back(types[column_ids[i].GetPrimaryIndex()]); } + chunk = make_uniq(); + chunk->Initialize(collection->GetAllocator(), scan_types); + + // initialize the scan + state = make_uniq(); + state->Initialize(column_ids, nullptr); + collection->InitializeScan(QueryContext(), state->local_state, column_ids, nullptr); + // scan the first chunk + this->operator++(); + } +} +RowGroupIterationHelper::RowGroupIterator::~RowGroupIterator() { +} + +RowGroupIterationHelper::RowGroupIterator::RowGroupIterator(RowGroupIterator &&other) noexcept { + std::swap(collection, other.collection); + std::swap(transaction, other.transaction); + std::swap(chunk, other.chunk); + std::swap(state, other.state); +} + +RowGroupIterationHelper::RowGroupIterator &RowGroupIterationHelper::RowGroupIterator::operator++() { + // scan the next chunk + chunk->Reset(); + state->local_state.Scan(*transaction, *chunk); + if (chunk->size() == 0) { + // done + collection = nullptr; + transaction = nullptr; + chunk.reset(); + state.reset(); } + return *this; +} + +bool RowGroupIterationHelper::RowGroupIterator::operator!=(const RowGroupIterator &other) const { + return collection != other.collection || transaction != other.transaction; +} + +DataChunk &RowGroupIterationHelper::RowGroupIterator::operator*() const { + return *chunk; } -bool RowGroupCollection::Scan(DuckTransaction &transaction, const std::function &fun) { +RowGroupIterationHelper RowGroupCollection::Chunks(DuckTransaction &transaction) { vector column_ids; column_ids.reserve(types.size()); for (idx_t i = 0; i < types.size(); i++) { column_ids.emplace_back(i); } - return Scan(transaction, column_ids, fun); + return Chunks(transaction, column_ids); +} + +RowGroupIterationHelper RowGroupCollection::Chunks(DuckTransaction &transaction, + const vector &column_ids) { + return RowGroupIterationHelper(*this, transaction, column_ids); } //===--------------------------------------------------------------------===// @@ -559,6 +611,10 @@ void RowGroupCollection::RevertAppendInternal(idx_t new_end_idx) { // we have no segments to revert return; } + auto last_segment = row_groups->GetLastSegment(l); + if (last_segment->GetRowEnd() <= new_end_idx) { + return; + } auto reverted_row_groups = make_shared_ptr(*this, row_groups->GetBaseRowId()); auto rlock = reverted_row_groups->Lock(); for (auto &entry : row_groups->SegmentNodes(l)) { @@ -627,6 +683,12 @@ void RowGroupCollection::MergeStorage(RowGroupCollection &data, optional_ptrGetNode(); if (!row_group.IsPersistent()) { + if (optimistically_written_count > 0) { +#ifdef DEBUG + throw InternalException("Partially optimistically written data at position %d (row start %d)", + entry->GetIndex(), entry->GetRowStart()); +#endif + } break; } optimistically_written_count += row_group.count; @@ -635,6 +697,7 @@ void RowGroupCollection::MergeStorage(RowGroupCollection &data, optional_ptr(); } } + bool is_persistent = segments.back()->GetNode().IsPersistent(); for (auto &entry : segments) { auto row_group = entry->MoveNode(); row_group->MoveToCollection(*this); @@ -654,6 +717,9 @@ void RowGroupCollection::MergeStorage(RowGroupCollection &data, optional_ptr indexed_column_id_set; - indexes.Scan([&](Index &index) { + + for (auto &index : indexes.Indexes()) { auto &set = index.GetColumnIdSet(); indexed_column_id_set.insert(set.begin(), set.end()); - return false; - }); + } // If we are in WAL replay, delete data will be buffered, and so we sort the column_ids // since the sorted form will be the mapping used to get back physical IDs from the buffered index chunk. @@ -912,7 +978,7 @@ void RowGroupCollection::RemoveFromIndexes(const QueryContext &context, TableInd DataChunk remaining_result_chunk; unique_ptr remaining_row_ids; - indexes.ScanEntries([&](IndexEntry &entry) { + for (auto &entry : indexes.IndexEntries()) { auto &index = *entry.index; if (index.IsBound()) { lock_guard guard(entry.lock); @@ -963,7 +1029,7 @@ void RowGroupCollection::RemoveFromIndexes(const QueryContext &context, TableInd if (targets.remove_target) { targets.remove_target->Delete(result_chunk, row_identifiers); } - return false; + continue; } // Buffering takes only the indexed columns in ordering of the column_ids mapping. DataChunk index_column_chunk; @@ -975,8 +1041,7 @@ void RowGroupCollection::RemoveFromIndexes(const QueryContext &context, TableInd index_column_chunk.SetCardinality(result_chunk.size()); auto &unbound_index = index.Cast(); unbound_index.BufferChunk(index_column_chunk, row_identifiers, column_ids, BufferedIndexReplay::DEL_ENTRY); - return false; - }); + } } void RowGroupCollection::UpdateColumn(TransactionData transaction, DataTable &data_table, Vector &row_ids, @@ -1394,7 +1459,7 @@ void RowGroupCollection::Checkpoint(TableDataWriter &writer, TableStatistics &gl try { // schedule tasks idx_t total_vacuum_tasks = 0; - auto max_vacuum_tasks = DBConfig::GetSetting(writer.GetDatabase()); + auto max_vacuum_tasks = Settings::Get(writer.GetDatabase()); for (idx_t segment_idx = 0; segment_idx < checkpoint_state.SegmentCount(); segment_idx++) { auto vacuum_tasks = ScheduleVacuumTasks(checkpoint_state, vacuum_state, segment_idx, total_vacuum_tasks < max_vacuum_tasks); @@ -1432,7 +1497,7 @@ void RowGroupCollection::Checkpoint(TableDataWriter &writer, TableStatistics &gl // no errors - finalize the row groups // if the table already exists on disk - check if all row groups have stayed the same - if (DBConfig::GetSetting(writer.GetDatabase()) && metadata_pointer.IsValid()) { + if (Settings::Get(writer.GetDatabase()) && metadata_pointer.IsValid()) { bool table_has_changes = false; for (idx_t segment_idx = 0; segment_idx < checkpoint_state.SegmentCount(); segment_idx++) { if (checkpoint_state.SegmentIsDropped(segment_idx)) { @@ -1511,7 +1576,7 @@ void RowGroupCollection::Checkpoint(TableDataWriter &writer, TableStatistics &gl new_row_group = entry->ReferenceNode(); } RowGroupPointer pointer_copy; - auto debug_verify_blocks = DBConfig::GetSetting(GetAttached().GetDatabase()) && + auto debug_verify_blocks = Settings::Get(GetAttached().GetDatabase()) && dynamic_cast(&checkpoint_state.writer) != nullptr; // check if we should write this row group to the persistent storage diff --git a/src/duckdb/src/storage/table/row_group_reorderer.cpp b/src/duckdb/src/storage/table/row_group_reorderer.cpp index 6f210a93e..554a47788 100644 --- a/src/duckdb/src/storage/table/row_group_reorderer.cpp +++ b/src/duckdb/src/storage/table/row_group_reorderer.cpp @@ -104,14 +104,13 @@ void InsertAllRowGroups(It it, End end, vector>> } void SetRowGroupVector(multimap &row_group_map, const optional_idx row_limit, - const idx_t row_group_offset, const RowGroupOrderType order_type, - const OrderByColumnType column_type, + const idx_t row_group_offset, const OrderType order_type, const OrderByColumnType column_type, vector>> &ordered_row_groups) { - const auto stat_type = order_type == RowGroupOrderType::ASC ? OrderByStatistics::MIN : OrderByStatistics::MAX; + const auto stat_type = order_type == OrderType::ASCENDING ? OrderByStatistics::MIN : OrderByStatistics::MAX; ordered_row_groups.reserve(row_group_map.size()); Value previous_key; - if (order_type == RowGroupOrderType::ASC) { + if (order_type == OrderType::ASCENDING) { auto it = SkipOffsetPrunedRowGroups(row_group_map.begin(), row_group_offset); auto end = row_group_map.end(); if (row_limit.IsValid()) { @@ -158,7 +157,7 @@ OffsetPruningResult FindOffsetPrunableChunks(It it, End end, const OrderByStatis if (!current_stats->CanHaveNull()) { // This row group has exactly row_group.count valid values. We can exclude those pruned_row_group_count++; - new_row_offset -= tuple_count; + new_row_offset -= last_unresolved_entry->second.count; } ++last_unresolved_entry; @@ -190,18 +189,35 @@ optional_ptr> RowGroupReorderer::GetNextRowGroup(SegmentNo Value RowGroupReorderer::RetrieveStat(const BaseStatistics &stats, OrderByStatistics order_by, OrderByColumnType column_type) { - switch (order_by) { - case OrderByStatistics::MIN: - return column_type == OrderByColumnType::NUMERIC ? NumericStats::Min(stats) : StringStats::Min(stats); - case OrderByStatistics::MAX: - return column_type == OrderByColumnType::NUMERIC ? NumericStats::Max(stats) : StringStats::Max(stats); + if (column_type == OrderByColumnType::NUMERIC) { + if (!NumericStats::HasMinMax(stats)) { + return Value(); + } + switch (order_by) { + case OrderByStatistics::MIN: + return NumericStats::Min(stats); + case OrderByStatistics::MAX: + return NumericStats::Max(stats); + default: + throw InternalException("Unsupported OrderByStatistics for numeric"); + } + } + if (column_type == OrderByColumnType::STRING) { + switch (order_by) { + case OrderByStatistics::MIN: + return StringStats::Min(stats); + case OrderByStatistics::MAX: + return StringStats::Max(stats); + default: + throw InternalException("Unsupported OrderByStatistics for numeric"); + } } - return Value(); + throw InternalException("Unsupported OrderByColumnType"); } OffsetPruningResult RowGroupReorderer::GetOffsetAfterPruning(const OrderByStatistics order_by, const OrderByColumnType column_type, - const RowGroupOrderType order_type, + const OrderType order_type, const StorageIndex &storage_index, const idx_t row_offset, vector &stats) { multimap ordered_row_groups; @@ -213,16 +229,23 @@ OffsetPruningResult RowGroupReorderer::GetOffsetAfterPruning(const OrderByStatis auto column_stats = partition_stats.partition_row_group->GetColumnStatistics(storage_index); Value comparison_value = RetrieveStat(*column_stats, order_by, column_type); + if (comparison_value.IsNull()) { + return {row_offset, 0}; + } auto entry = RowGroupOffsetEntry {partition_stats.count, std::move(column_stats)}; ordered_row_groups.emplace(comparison_value, std::move(entry)); } - if (order_type == RowGroupOrderType::ASC) { + switch (order_type) { + case OrderType::ASCENDING: return FindOffsetPrunableChunks(ordered_row_groups.begin(), ordered_row_groups.end(), order_by, column_type, row_offset); + case OrderType::DESCENDING: + return FindOffsetPrunableChunks(ordered_row_groups.rbegin(), ordered_row_groups.rend(), order_by, column_type, + row_offset); + default: + throw InternalException("Unsupported order type in GetOffsetAfterPruning"); } - return FindOffsetPrunableChunks(ordered_row_groups.rbegin(), ordered_row_groups.rend(), order_by, column_type, - row_offset); } optional_ptr> RowGroupReorderer::GetRootSegment(RowGroupSegmentTree &row_groups) { @@ -235,10 +258,16 @@ optional_ptr> RowGroupReorderer::GetRootSegment(RowGroupSe initialized = true; + vector>> remaining_row_groups; multimap row_group_map; for (auto &row_group : row_groups.SegmentNodes()) { auto stats = row_group.GetNode().GetStatistics(options.column_idx); Value comparison_value = RetrieveStat(*stats, options.order_by, options.column_type); + if (comparison_value.IsNull()) { + // no stats for this row group - push to remaining + remaining_row_groups.push_back(row_group); + continue; + } auto entry = RowGroupSegmentNodeEntry {row_group, std::move(stats)}; row_group_map.emplace(comparison_value, std::move(entry)); } @@ -250,6 +279,10 @@ optional_ptr> RowGroupReorderer::GetRootSegment(RowGroupSe D_ASSERT(row_group_map.size() > options.row_group_offset); SetRowGroupVector(row_group_map, options.row_limit, options.row_group_offset, options.order_type, options.column_type, ordered_row_groups); + // push any remaining row groups + for (auto &remaining_row_group : remaining_row_groups) { + ordered_row_groups.push_back(remaining_row_group); + } return ordered_row_groups[0].get(); } diff --git a/src/duckdb/src/storage/table/row_id_column_data.cpp b/src/duckdb/src/storage/table/row_id_column_data.cpp index 235244c19..0c648892b 100644 --- a/src/duckdb/src/storage/table/row_id_column_data.cpp +++ b/src/duckdb/src/storage/table/row_id_column_data.cpp @@ -155,7 +155,8 @@ unique_ptr RowIdColumnData::CreateCheckpointState(const R throw InternalException("RowIdColumnData cannot be checkpointed"); } -unique_ptr RowIdColumnData::Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info) { +unique_ptr RowIdColumnData::Checkpoint(const RowGroup &row_group, ColumnCheckpointInfo &info, + const BaseStatistics &old_stats) { throw InternalException("RowIdColumnData cannot be checkpointed"); } diff --git a/src/duckdb/src/storage/table/standard_column_data.cpp b/src/duckdb/src/storage/table/standard_column_data.cpp index 0f84aa0b8..7e43eaae8 100644 --- a/src/duckdb/src/storage/table/standard_column_data.cpp +++ b/src/duckdb/src/storage/table/standard_column_data.cpp @@ -150,11 +150,9 @@ void StandardColumnData::Update(TransactionData transaction, DataTable &data_tab ColumnScanState standard_state(nullptr); ColumnScanState validity_state(nullptr); Vector base_vector(type); - auto standard_fetch = FetchUpdateData(standard_state, row_ids, base_vector, row_group_start); - auto validity_fetch = validity->FetchUpdateData(validity_state, row_ids, base_vector, row_group_start); - if (standard_fetch != validity_fetch) { - throw InternalException("Unaligned fetch in validity and main column data for update"); - } + + FetchUpdateData(standard_state, row_ids, base_vector, row_group_start); + validity->FetchUpdateData(validity_state, row_ids, base_vector, row_group_start); UpdateInternal(transaction, data_table, column_index, update_vector, row_ids, update_count, base_vector, row_group_start); @@ -260,7 +258,8 @@ StandardColumnData::CreateCheckpointState(const RowGroup &row_group, PartialBloc } unique_ptr StandardColumnData::Checkpoint(const RowGroup &row_group, - ColumnCheckpointInfo &checkpoint_info) { + ColumnCheckpointInfo &checkpoint_info, + const BaseStatistics &stats) { // we need to checkpoint the main column data first // that is because the checkpointing of the main column data ALSO scans the validity data // to prevent reading the validity data immediately after it is checkpointed we first checkpoint the main column diff --git a/src/duckdb/src/storage/table/struct_column_data.cpp b/src/duckdb/src/storage/table/struct_column_data.cpp index 7d134f60c..0ab6ab90e 100644 --- a/src/duckdb/src/storage/table/struct_column_data.cpp +++ b/src/duckdb/src/storage/table/struct_column_data.cpp @@ -48,9 +48,8 @@ idx_t StructColumnData::GetMaxEntry() { return sub_columns[0]->GetMaxEntry(); } -void StructColumnData::IterateFields( - ColumnScanState &state, - const std::function &callback) { +vector StructColumnData::GetStructChildren(ColumnScanState &state) const { + vector res; if (state.storage_index.IsPushdownExtract()) { auto &index_children = state.storage_index.GetChildIndexes(); D_ASSERT(index_children.size() == 1); @@ -58,25 +57,25 @@ void StructColumnData::IterateFields( auto child_index = child_storage_index.GetPrimaryIndex(); auto &field_state = state.child_states[1]; D_ASSERT(state.scan_child_column[0]); - callback(child_index, optional_idx(), field_state, true); + res.emplace_back(*sub_columns[child_index], optional_idx(), field_state, true); } else { for (idx_t i = 0; i < sub_columns.size(); i++) { auto &field_state = state.child_states[1 + i]; - callback(i, i, field_state, state.scan_child_column[i]); + res.emplace_back(*sub_columns[i], i, field_state, state.scan_child_column[i]); } } + return res; } void StructColumnData::InitializePrefetch(PrefetchState &prefetch_state, ColumnScanState &scan_state, idx_t rows) { validity->InitializePrefetch(prefetch_state, scan_state.child_states[0], rows); - IterateFields(scan_state, [&](idx_t child_index, optional_idx field_vector_index, ColumnScanState &field_state, - bool should_scan) { - if (!should_scan) { - return; + auto struct_children = GetStructChildren(scan_state); + for (auto &child : struct_children) { + if (!child.should_scan) { + continue; } - auto &field = *sub_columns[child_index]; - field.InitializePrefetch(prefetch_state, field_state, rows); - }); + child.col.InitializePrefetch(prefetch_state, child.state, rows); + } } void StructColumnData::InitializeScan(ColumnScanState &state) { @@ -87,14 +86,13 @@ void StructColumnData::InitializeScan(ColumnScanState &state) { validity->InitializeScan(state.child_states[0]); // initialize the sub-columns - IterateFields( - state, [&](idx_t child_index, optional_idx field_vector_index, ColumnScanState &field_state, bool should_scan) { - if (!should_scan) { - return; - } - auto &field = *sub_columns[child_index]; - field.InitializeScan(field_state); - }); + auto struct_children = GetStructChildren(state); + for (auto &child : struct_children) { + if (!child.should_scan) { + continue; + } + child.col.InitializeScan(child.state); + } } void StructColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) { @@ -106,14 +104,13 @@ void StructColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t ro validity->InitializeScanWithOffset(state.child_states[0], row_idx); // initialize the sub-columns - IterateFields( - state, [&](idx_t child_index, optional_idx field_vector_index, ColumnScanState &field_state, bool should_scan) { - if (!should_scan) { - return; - } - auto &field = *sub_columns[child_index]; - field.InitializeScanWithOffset(field_state, row_idx); - }); + auto struct_children = GetStructChildren(state); + for (auto &child : struct_children) { + if (!child.should_scan) { + continue; + } + child.col.InitializeScanWithOffset(child.state, row_idx); + } } static Vector &GetFieldVectorForScan(Vector &result, optional_idx field_index) { @@ -148,39 +145,38 @@ static void ScanChild(ColumnScanState &state, Vector &result, const std::functio idx_t StructColumnData::Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, idx_t target_count) { auto scan_count = validity->Scan(transaction, vector_index, state.child_states[0], result, target_count); - IterateFields( - state, [&](idx_t child_index, optional_idx field_vector_index, ColumnScanState &field_state, bool should_scan) { - auto &target_vector = GetFieldVectorForScan(result, field_vector_index); - if (!should_scan) { - // if we are not scanning this vector - set it to NULL - target_vector.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(target_vector, true); - return; - } - auto &field = *sub_columns[child_index]; - ScanChild(state, target_vector, [&](Vector &child_result) { - return field.Scan(transaction, vector_index, field_state, child_result, target_count); - }); - }); + auto struct_children = GetStructChildren(state); + for (auto &child : struct_children) { + auto &target_vector = GetFieldVectorForScan(result, child.vector_index); + if (!child.should_scan) { + // if we are not scanning this vector - set it to NULL + target_vector.SetVectorType(VectorType::CONSTANT_VECTOR); + ConstantVector::SetNull(target_vector, true); + continue; + } + ScanChild(state, target_vector, [&](Vector &child_result) { + return child.col.Scan(transaction, vector_index, child.state, child_result, target_count); + }); + } return scan_count; } idx_t StructColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t count, idx_t result_offset) { auto scan_count = validity->ScanCount(state.child_states[0], result, count); - IterateFields( - state, [&](idx_t child_index, optional_idx field_vector_index, ColumnScanState &field_state, bool should_scan) { - auto &target_vector = GetFieldVectorForScan(result, field_vector_index); - if (!should_scan) { - // if we are not scanning this vector - set it to NULL - target_vector.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(target_vector, true); - return; - } - auto &field = *sub_columns[child_index]; - ScanChild(state, target_vector, [&](Vector &child_result) { - return field.ScanCount(field_state, child_result, count, result_offset); - }); - }); + + auto struct_children = GetStructChildren(state); + for (auto &child : struct_children) { + auto &target_vector = GetFieldVectorForScan(result, child.vector_index); + if (!child.should_scan) { + // if we are not scanning this vector - set it to NULL + target_vector.SetVectorType(VectorType::CONSTANT_VECTOR); + ConstantVector::SetNull(target_vector, true); + continue; + } + ScanChild(state, target_vector, [&](Vector &child_result) { + return child.col.ScanCount(child.state, child_result, count, result_offset); + }); + } return scan_count; } @@ -188,14 +184,13 @@ void StructColumnData::Skip(ColumnScanState &state, idx_t count) { validity->Skip(state.child_states[0], count); // skip inside the sub-columns - IterateFields( - state, [&](idx_t child_index, optional_idx field_vector_index, ColumnScanState &field_state, bool should_scan) { - if (!should_scan) { - return; - } - auto &field = *sub_columns[child_index]; - field.Skip(field_state, count); - }); + auto struct_children = GetStructChildren(state); + for (auto &child : struct_children) { + if (!child.should_scan) { + continue; + } + child.col.Skip(child.state, count); + } } void StructColumnData::InitializeAppend(ColumnAppendState &state) { @@ -357,6 +352,29 @@ void StructColumnData::SetChildData(idx_t i, shared_ptr child_column this->sub_columns[i] = std::move(child_column_p); } +const ColumnData &StructColumnData::GetChildColumn(idx_t index) const { + D_ASSERT(index < sub_columns.size()); + return *sub_columns[index]; +} + +const BaseStatistics &StructColumnData::GetChildStats(const ColumnData &child) const { + optional_idx index; + for (idx_t i = 0; i < sub_columns.size(); i++) { + if (RefersToSameObject(child, *sub_columns[i])) { + index = i; + break; + } + } + if (!index.IsValid()) { + throw InternalException("StructColumnData::GetChildStats: Could not find a matching child index for the " + "provided child (of type %s)", + child.type.ToString()); + } + auto idx = index.GetIndex(); + auto &stats = GetStatisticsRef(); + return StructStats::GetChildStats(stats, idx); +} + struct StructColumnCheckpointState : public ColumnCheckpointState { StructColumnCheckpointState(const RowGroup &row_group, ColumnData &column_data, PartialBlockManager &partial_block_manager) @@ -411,12 +429,16 @@ unique_ptr StructColumnData::CreateCheckpointState(const } unique_ptr StructColumnData::Checkpoint(const RowGroup &row_group, - ColumnCheckpointInfo &checkpoint_info) { + ColumnCheckpointInfo &checkpoint_info, + const BaseStatistics &old_stats) { auto &partial_block_manager = checkpoint_info.GetPartialBlockManager(); auto checkpoint_state = make_uniq(row_group, *this, partial_block_manager); - checkpoint_state->validity_state = validity->Checkpoint(row_group, checkpoint_info); - for (auto &sub_column : sub_columns) { - checkpoint_state->child_states.push_back(sub_column->Checkpoint(row_group, checkpoint_info)); + checkpoint_state->validity_state = validity->Checkpoint(row_group, checkpoint_info, old_stats); + + for (idx_t col_idx = 0; col_idx < sub_columns.size(); col_idx++) { + const auto &sub_column = sub_columns[col_idx]; + const auto &old_child_stats = StructStats::GetChildStats(old_stats, col_idx); + checkpoint_state->child_states.push_back(sub_column->Checkpoint(row_group, checkpoint_info, old_child_stats)); } return std::move(checkpoint_state); } diff --git a/src/duckdb/src/storage/table/variant/variant_shredding.cpp b/src/duckdb/src/storage/table/variant/variant_shredding.cpp index e0485626d..198abd272 100644 --- a/src/duckdb/src/storage/table/variant/variant_shredding.cpp +++ b/src/duckdb/src/storage/table/variant/variant_shredding.cpp @@ -241,7 +241,8 @@ struct DuckDBVariantShredding : public VariantShredding { void WriteVariantValues(UnifiedVariantVectorData &variant, Vector &result, optional_ptr sel, optional_ptr value_index_sel, optional_ptr result_sel, idx_t count) override; - void AnalyzeVariantValues(UnifiedVariantVectorData &variant, Vector &value, optional_ptr sel, + void AnalyzeVariantValues(UnifiedVariantVectorData &variant, optional_ptr untyped_values, + optional_ptr sel, optional_ptr value_index_sel, optional_ptr result_sel, DuckDBVariantShreddingState &shredding_state, idx_t count); @@ -367,19 +368,33 @@ static LogicalType ProduceShreddedType(VariantLogicalType type_id) { } } -static LogicalType SetShreddedType(const LogicalType &typed_value) { +static bool CanFlattenShreddedType(const LogicalType &type) { + if (type.IsNested()) { + // cannot flatten nested types + return false; + } + return true; +} + +static LogicalType SetShreddedType(const LogicalType &typed_value, bool fully_consistent) { + if (fully_consistent && CanFlattenShreddedType(typed_value)) { + // fully consistent and this is a primitive type - we can flatten the type entirely + return typed_value; + } child_list_t child_types; - child_types.emplace_back("untyped_value_index", LogicalType::UINTEGER); child_types.emplace_back("typed_value", typed_value); + if (!fully_consistent) { + child_types.emplace_back("untyped_value_index", LogicalType::UINTEGER); + } return LogicalType::STRUCT(child_types); } bool VariantShreddingStats::GetShreddedTypeInternal(const VariantColumnStatsData &column, LogicalType &out_type) const { idx_t max_count = 0; - uint8_t type_index; + uint8_t type_index = 0; if (column.type_counts[0] == column.total_count) { //! All NULL, emit INT32 - out_type = SetShreddedType(LogicalTypeId::INTEGER); + out_type = SetShreddedType(LogicalTypeId::INTEGER, true); return true; } @@ -389,7 +404,7 @@ bool VariantShreddingStats::GetShreddedTypeInternal(const VariantColumnStatsData //! Can't shred on DECIMAL, not consistent continue; } - idx_t count = column.type_counts[i]; + idx_t count = column.type_counts[i] + column.type_counts[0]; if (!max_count || count > max_count) { max_count = count; type_index = i; @@ -400,6 +415,7 @@ bool VariantShreddingStats::GetShreddedTypeInternal(const VariantColumnStatsData return false; } + bool fully_consistent = max_count == column.total_count; if (type_index == static_cast(VariantLogicalType::OBJECT)) { child_list_t child_types; for (auto &entry : column.field_stats) { @@ -413,7 +429,7 @@ bool VariantShreddingStats::GetShreddedTypeInternal(const VariantColumnStatsData return false; } auto shredded_type = LogicalType::STRUCT(child_types); - out_type = SetShreddedType(shredded_type); + out_type = SetShreddedType(shredded_type, fully_consistent); return true; } if (type_index == static_cast(VariantLogicalType::ARRAY)) { @@ -424,19 +440,19 @@ bool VariantShreddingStats::GetShreddedTypeInternal(const VariantColumnStatsData return false; } auto shredded_type = LogicalType::LIST(element_type); - out_type = SetShreddedType(shredded_type); + out_type = SetShreddedType(shredded_type, fully_consistent); return true; } if (type_index == static_cast(VariantLogicalType::DECIMAL)) { auto shredded_type = LogicalType::DECIMAL(static_cast(column.decimal_width), static_cast(column.decimal_scale)); - out_type = SetShreddedType(shredded_type); + out_type = SetShreddedType(shredded_type, fully_consistent); return true; } auto type_id = static_cast(type_index); auto shredded_type = ProduceShreddedType(type_id); - out_type = SetShreddedType(shredded_type); + out_type = SetShreddedType(shredded_type, fully_consistent); return true; } @@ -522,13 +538,18 @@ static vector UnshreddedObjectChildren(UnifiedVariantVectorData &varia //! ~~Write the unshredded values~~, also receiving the 'untyped_value_index' Vector to populate //! Marking the rows that are shredded in the shredding state -void DuckDBVariantShredding::AnalyzeVariantValues(UnifiedVariantVectorData &variant, Vector &value, +void DuckDBVariantShredding::AnalyzeVariantValues(UnifiedVariantVectorData &variant, + optional_ptr untyped_values, optional_ptr sel, optional_ptr value_index_sel, optional_ptr result_sel, DuckDBVariantShreddingState &shredding_state, idx_t count) { - auto &validity = FlatVector::Validity(value); - auto untyped_data = FlatVector::GetData(value); + // + // auto &validity = FlatVector::Validity(value); + uint32_t *untyped_data = nullptr; + if (untyped_values) { + untyped_data = FlatVector::GetData(*untyped_values); + } for (uint32_t i = 0; i < static_cast(count); i++) { uint32_t value_index = 0; @@ -549,8 +570,10 @@ void DuckDBVariantShredding::AnalyzeVariantValues(UnifiedVariantVectorData &vari if (variant.RowIsValid(row) && shredding_state.ValueIsShredded(variant, row, value_index)) { shredding_state.SetShredded(row, value_index, result_index); if (shredding_state.type.id() != LogicalTypeId::STRUCT) { - //! Value is shredded, directly write a NULL to the 'value' if the type is not an OBJECT - validity.SetInvalid(result_index); + //! Value is shredded, directly write a `NULL` to the 'value' if the type is not an OBJECT + if (untyped_values) { + FlatVector::Validity(*untyped_values).SetInvalid(result_index); + } continue; } @@ -558,9 +581,15 @@ void DuckDBVariantShredding::AnalyzeVariantValues(UnifiedVariantVectorData &vari auto unshredded_children = UnshreddedObjectChildren(variant, row, value_index, shredding_state); if (unshredded_children.empty()) { //! Fully shredded object - validity.SetInvalid(result_index); + if (untyped_values) { + FlatVector::Validity(*untyped_values).SetInvalid(result_index); + } } else { //! Deal with partially shredded objects + if (!untyped_data) { + throw InvalidInputException( + "Failed to shred variant value - untyped_value was not set but inconsistent values were found"); + } unshredded_values[row].emplace_back(value_index, untyped_data[result_index], std::move(unshredded_children)); } @@ -569,29 +598,43 @@ void DuckDBVariantShredding::AnalyzeVariantValues(UnifiedVariantVectorData &vari //! Deal with unshredded values if (!variant.RowIsValid(row) || variant.GetTypeId(row, value_index) == VariantLogicalType::VARIANT_NULL) { - //! 0 is reserved for NULL - untyped_data[result_index] = 0; + //! NULL is reserved for NULL Variant values + if (untyped_values) { + FlatVector::Validity(*untyped_values).SetInvalid(result_index); + } } else { + if (!untyped_data) { + throw InvalidInputException( + "Failed to shred variant value - untyped_value was not set but inconsistent values were found"); + } unshredded_values[row].emplace_back(value_index, untyped_data[result_index]); } } } -//! Receive a 'shredded' result Vector, consisting of the 'untyped_value_index' and the 'typed_value' Vector +//! Receive a 'shredded' result Vector, consisting of the 'typed_value' and the 'untyped_value_index' Vector void DuckDBVariantShredding::WriteVariantValues(UnifiedVariantVectorData &variant, Vector &result, optional_ptr sel, optional_ptr value_index_sel, optional_ptr result_sel, idx_t count) { - auto &child_vectors = StructVector::GetEntries(result); + reference typed_value_ref(result); + optional_ptr untyped_value_index; + if (result.GetType().id() == LogicalTypeId::STRUCT) { + // "typed_value", "untyped_value" + auto &child_vectors = StructVector::GetEntries(result); #ifdef D_ASSERT_IS_ENABLED - auto &result_type = result.GetType(); - D_ASSERT(result_type.id() == LogicalTypeId::STRUCT); - auto &child_types = StructType::GetChildTypes(result_type); - D_ASSERT(child_types.size() == child_vectors.size()); + auto &result_type = result.GetType(); + D_ASSERT(result_type.id() == LogicalTypeId::STRUCT); + auto &child_types = StructType::GetChildTypes(result_type); + D_ASSERT(child_types.size() == child_vectors.size()); #endif - - auto &untyped_value_index = *child_vectors[0]; - auto &typed_value = *child_vectors[1]; + typed_value_ref = *child_vectors[VariantColumnData::TYPED_VALUE_INDEX]; + if (child_vectors.size() > 1) { + D_ASSERT(child_vectors.size() == 2); + untyped_value_index = *child_vectors[VariantColumnData::UNTYPED_VALUE_INDEX]; + } + } + auto &typed_value = typed_value_ref.get(); DuckDBVariantShreddingState shredding_state(typed_value.GetType(), count); AnalyzeVariantValues(variant, untyped_value_index, sel, value_index_sel, result_sel, shredding_state, count); diff --git a/src/duckdb/src/storage/table/variant/variant_unshredding.cpp b/src/duckdb/src/storage/table/variant/variant_unshredding.cpp index 3b8e02488..307e4e317 100644 --- a/src/duckdb/src/storage/table/variant/variant_unshredding.cpp +++ b/src/duckdb/src/storage/table/variant/variant_unshredding.cpp @@ -14,15 +14,14 @@ static VariantValue UnshreddedVariantValue(UnifiedVariantVectorData &input, uint } if (values_index == 0) { - //! 0 is reserved to indicate NULL, to better recognize the situation where a Variant is fully shredded, but has - //! NULLs - return VariantValue(Value(LogicalTypeId::SQLNULL)); + //! 0 is reserved to indicate a missing value + return VariantValue(VariantValueType::MISSING); } values_index--; auto type_id = input.GetTypeId(row, values_index); if (!ALLOW_NULL) { - //! We don't expect NULLs at the root, those should have the 'values_index' of 0 + //! We don't expect NULLs at the root, those should have a NULL 'untyped_value_index' D_ASSERT(type_id != VariantLogicalType::VARIANT_NULL); } @@ -68,9 +67,10 @@ static vector UnshredTypedLeaf(Vector &typed_value, idx_t count) { for (idx_t i = 0; i < count; i++) { if (!typed_value_validity.RowIsValid(vector_format.sel->get_index(i))) { - continue; + res[i] = VariantValue(Value(LogicalTypeId::SQLNULL)); + } else { + res[i] = VariantValue(typed_value.GetValue(i)); } - res[i] = VariantValue(typed_value.GetValue(i)); } return res; } @@ -100,15 +100,19 @@ static vector UnshredTypedObject(UnifiedVariantVectorData &variant auto &values = child_values[child_idx]; for (idx_t i = 0; i < count; i++) { - if (!typed_value_validity.RowIsValid(vector_format.sel->get_index(i))) { - continue; - } if (values[i].IsMissing()) { + // struct field is missing continue; } - if (res[i].IsMissing()) { + if (!typed_value_validity.RowIsValid(vector_format.sel->get_index(i))) { + res[i] = VariantValue(Value(LogicalTypeId::SQLNULL)); + } else if (res[i].IsMissing()) { res[i] = VariantValue(VariantValueType::OBJECT); } + if (res[i].IsNull()) { + // struct itself is NULL + continue; + } auto &obj_value = res[i]; obj_value.AddChild(child_name, std::move(values[i])); } @@ -129,8 +133,11 @@ static vector UnshredTypedArray(UnifiedVariantVectorData &variant, auto &typed_value_validity = vector_format.validity; SelectionVector child_sel(child_size); + vector res(count); for (uint32_t i = 0; i < count; i++) { if (!typed_value_validity.RowIsValid(vector_format.sel->get_index(i))) { + // array itself is NULL + res[i] = VariantValue(Value(LogicalType::SQLNULL)); continue; } auto row = row_sel ? static_cast(row_sel->get_index(i)) : i; @@ -141,9 +148,8 @@ static vector UnshredTypedArray(UnifiedVariantVectorData &variant, } auto child_values = Unshred(variant, child_vector, child_size, child_sel); - vector res(count); for (idx_t i = 0; i < count; i++) { - if (!typed_value_validity.RowIsValid(vector_format.sel->get_index(i))) { + if (res[i].IsNull()) { continue; } auto &list_entry = list_data[i]; @@ -175,31 +181,51 @@ static vector UnshredTypedValue(UnifiedVariantVectorData &variant, static vector Unshred(UnifiedVariantVectorData &variant, Vector &shredded, idx_t count, optional_ptr row_sel) { - D_ASSERT(shredded.GetType().id() == LogicalTypeId::STRUCT); - auto &child_entries = StructVector::GetEntries(shredded); - D_ASSERT(child_entries.size() == 2); + reference typed_value_ref(shredded); + optional_ptr untyped_value_index; + if (shredded.GetType().id() == LogicalTypeId::STRUCT) { + // "typed_value", "untyped_value" + auto &child_vectors = StructVector::GetEntries(shredded); + D_ASSERT(shredded.GetType().id() == LogicalTypeId::STRUCT); + auto &child_entries = StructVector::GetEntries(shredded); + D_ASSERT(child_entries.size() <= 2); + typed_value_ref = *child_vectors[VariantColumnData::TYPED_VALUE_INDEX]; + if (child_vectors.size() > 1) { + D_ASSERT(child_vectors.size() == 2); + untyped_value_index = *child_vectors[VariantColumnData::UNTYPED_VALUE_INDEX]; + } + } + auto &typed_value = typed_value_ref.get(); - auto &untyped_value_index = *child_entries[0]; - auto &typed_value = *child_entries[1]; + // unshred the typed variant + auto res = UnshredTypedValue(variant, typed_value, count, row_sel); + if (!untyped_value_index) { + return res; + } + // if we have any untyped values - unshred them UnifiedVectorFormat untyped_format; - untyped_value_index.ToUnifiedFormat(count, untyped_format); + untyped_value_index->ToUnifiedFormat(count, untyped_format); auto untyped_index_data = untyped_format.GetData(untyped_format); auto &untyped_index_validity = untyped_format.validity; - - auto res = UnshredTypedValue(variant, typed_value, count, row_sel); for (uint32_t i = 0; i < count; i++) { if (!untyped_index_validity.RowIsValid(untyped_format.sel->get_index(i))) { + //! NULL untyped_value_index indicates a fully shredded variant continue; } auto value_index = untyped_index_data[untyped_format.sel->get_index(i)]; + if (value_index == 0) { + // untyped value index of 0 indicates missing + res[i] = VariantValue(VariantValueType::MISSING); + continue; + } auto row = row_sel ? static_cast(row_sel->get_index(i)) : i; auto unshredded = UnshreddedVariantValue(variant, row, value_index); - if (res[i].IsMissing()) { + if (res[i].IsNull()) { //! Unshredded, has no shredded value res[i] = std::move(unshredded); - } else if (!unshredded.IsNull()) { + } else { //! Partial shredding, already has a shredded value that this has to be combined into D_ASSERT(res[i].value_type == VariantValueType::OBJECT); D_ASSERT(unshredded.value_type == VariantValueType::OBJECT); diff --git a/src/duckdb/src/storage/table/variant_column_data.cpp b/src/duckdb/src/storage/table/variant_column_data.cpp index cf168902a..d349239c6 100644 --- a/src/duckdb/src/storage/table/variant_column_data.cpp +++ b/src/duckdb/src/storage/table/variant_column_data.cpp @@ -1,10 +1,14 @@ #include "duckdb/storage/table/variant_column_data.hpp" +#include "duckdb/storage/table/struct_column_data.hpp" #include "duckdb/common/serializer/deserializer.hpp" #include "duckdb/storage/table/column_checkpoint_state.hpp" #include "duckdb/storage/table/append_state.hpp" #include "duckdb/storage/table/scan_state.hpp" #include "duckdb/storage/statistics/variant_stats.hpp" +#include "duckdb/storage/statistics/struct_stats.hpp" #include "duckdb/function/variant/variant_shredding.hpp" +#include "duckdb/main/settings.hpp" +#include "duckdb/transaction/duck_transaction.hpp" namespace duckdb { @@ -27,6 +31,106 @@ VariantColumnData::VariantColumnData(BlockManager &block_manager, DataTableInfo } } +bool FindShreddedColumnInternal(const ColumnData &shredded, reference &stats, + reference &path_iter, ColumnIndex &out) { + auto &path = path_iter.get(); + D_ASSERT(!path.HasPrimaryIndex()); + auto &field_name = path.GetFieldName(); + if (!path.HasChildren()) { + // end of the line + if (!VariantShreddedStats::IsFullyShredded(stats.get())) { + //! Child isn't fully shredded, can't use it + return false; + } + //! We're done, we've found the field referenced by the path! + if (shredded.type.id() == LogicalTypeId::STRUCT) { + // if this is a struct - refer to the .typed_value field + out.AddChildIndex(ColumnIndex(VariantColumnData::TYPED_VALUE_INDEX)); + stats = StructStats::GetChildStats(stats.get(), VariantColumnData::TYPED_VALUE_INDEX); + } + return true; + } + if (shredded.type.id() != LogicalTypeId::STRUCT) { + // we're looking for a sub-field but this is a primitive type - not a match + return false; + } + + D_ASSERT(shredded.type.id() == LogicalTypeId::STRUCT); + auto &struct_col = shredded.Cast(); + auto &typed_value = struct_col.GetChildColumn(VariantColumnData::TYPED_VALUE_INDEX); + auto &parent_stats = stats.get(); + + stats = StructStats::GetChildStats(parent_stats, VariantColumnData::TYPED_VALUE_INDEX); + if (typed_value.type.id() != LogicalTypeId::STRUCT) { + //! Not shredded on an OBJECT, but we're looking for a specific OBJECT field + return false; + } + if (!VariantShreddedStats::IsFullyShredded(parent_stats)) { + //! Can't push down to the shredded data, stats are inconsistent + return false; + } + //! shredded.typed_value + out.AddChildIndex(ColumnIndex(VariantColumnData::TYPED_VALUE_INDEX)); + auto &typed_value_index = out.GetChildIndex(0); + + auto &object_children = StructType::GetChildTypes(typed_value.type); + optional_idx opt_index; + for (idx_t i = 0; i < object_children.size(); i++) { + if (StringUtil::CIEquals(field_name, object_children[i].first)) { + opt_index = i; + break; + } + } + if (!opt_index.IsValid()) { + //! OBJECT doesn't contain a field with this name + return false; + } + + auto child_index = opt_index.GetIndex(); + auto &typed_value_struct = typed_value.Cast(); + auto &object_field = typed_value_struct.GetChildColumn(child_index); + stats = StructStats::GetChildStats(stats.get(), child_index); + + //! typed_value. + typed_value_index.AddChildIndex(ColumnIndex(child_index)); + auto &child_column = typed_value_index.GetChildIndex(0); + + // recurse + path_iter = path.GetChildIndex(0); + return FindShreddedColumnInternal(object_field, stats, path_iter, child_column); +} + +bool VariantColumnData::PushdownShreddedFieldExtract(const StorageIndex &variant_extract, + StorageIndex &out_struct_extract) const { + D_ASSERT(IsShredded()); + auto &shredded = *sub_columns[1]; + auto &variant_stats = GetStatisticsRef(); + + if (!VariantStats::IsShredded(variant_stats)) { + //! FIXME: this happens when we Checkpoint but don't restart, the stats of the ColumnData aren't updated by + //! Checkpoint The variant is shredded, but there are no stats / the stats are cluttered (?) + return false; + } + + //! shredded.typed_value + ColumnIndex column_index(0); + + reference shredded_stats(VariantStats::GetShreddedStats(variant_stats)); + reference path_iter(variant_extract); + if (!FindShreddedColumnInternal(shredded, shredded_stats, path_iter, column_index)) { + return false; + } + if (shredded_stats.get().GetType().IsNested()) { + //! Can't push down an extract if the leaf we're extracting is not a primitive + //! (Since the shredded representation for OBJECT/ARRAY is interleaved with 'untyped_value_index' fields) + return false; + } + + column_index.SetPushdownExtractType(shredded.type, path_iter.get().GetType()); + out_struct_extract = StorageIndex::FromColumnIndex(column_index); + return true; +} + void VariantColumnData::CreateScanStates(ColumnScanState &state) { //! Re-initialize the scan state, since VARIANT can have a different shape for every RowGroup state.child_states.clear(); @@ -37,9 +141,22 @@ void VariantColumnData::CreateScanStates(ColumnScanState &state) { auto unshredded_type = VariantShredding::GetUnshreddedType(); state.child_states.emplace_back(state.parent); state.child_states[1].Initialize(state.context, unshredded_type, state.scan_options); + + const bool is_pushed_down_cast = + state.storage_index.HasType() && state.storage_index.GetScanType().id() != LogicalTypeId::VARIANT; if (IsShredded()) { auto &shredded_column = sub_columns[1]; state.child_states.emplace_back(state.parent); + if (state.storage_index.IsPushdownExtract() && is_pushed_down_cast) { + StorageIndex struct_extract; + if (PushdownShreddedFieldExtract(state.storage_index.GetChildIndex(0), struct_extract)) { + //! Shredded field exists and is fully shredded, + //! add the storage index to create a pushed-down 'struct_extract' to get the leaf + state.child_states[2].Initialize(state.context, shredded_column->type, struct_extract, + state.scan_options); + return; + } + } state.child_states[2].Initialize(state.context, shredded_column->type, state.scan_options); } } @@ -49,6 +166,7 @@ idx_t VariantColumnData::GetMaxEntry() { } void VariantColumnData::InitializePrefetch(PrefetchState &prefetch_state, ColumnScanState &scan_state, idx_t rows) { + //! FIXME: does this also need CreateScanStates ?? validity->InitializePrefetch(prefetch_state, scan_state.child_states[0], rows); for (idx_t i = 0; i < sub_columns.size(); i++) { sub_columns[i]->InitializePrefetch(prefetch_state, scan_state.child_states[i + 1], rows); @@ -81,7 +199,7 @@ void VariantColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t r } } -Vector VariantColumnData::CreateUnshreddingIntermediate(idx_t count) { +Vector VariantColumnData::CreateUnshreddingIntermediate(idx_t count) const { D_ASSERT(IsShredded()); D_ASSERT(sub_columns.size() == 2); @@ -93,26 +211,119 @@ Vector VariantColumnData::CreateUnshreddingIntermediate(idx_t count) { return intermediate; } -idx_t VariantColumnData::Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - idx_t target_count) { - if (IsShredded()) { - auto intermediate = CreateUnshreddingIntermediate(target_count); - auto &child_vectors = StructVector::GetEntries(intermediate); - sub_columns[0]->Scan(transaction, vector_index, state.child_states[1], *child_vectors[0], target_count); - sub_columns[1]->Scan(transaction, vector_index, state.child_states[2], *child_vectors[1], target_count); - auto scan_count = validity->Scan(transaction, vector_index, state.child_states[0], intermediate, target_count); +idx_t VariantColumnData::ScanWithCallback( + ColumnScanState &state, Vector &result, idx_t target_count, + const std::function + &callback) const { + if (state.storage_index.IsPushdownExtract()) { + if (IsShredded() && state.child_states[2].storage_index.IsPushdownExtract()) { + //! FIXME: We could also push down the extract if we're returning VARIANT + //! Then we can do the unshredding on the extracted data, rather than falling back to unshredding+extracting + //! This invariant is ensured by CreateScanStates + D_ASSERT(result.GetType().id() != LogicalTypeId::VARIANT); + + //! In the initialize we have verified that the field exists and the data is fully shredded (for this + //! rowgroup) We have created a scan state that performs a 'struct_extract' in the shredded data, to extract + //! the requested field.s + auto res = callback(*sub_columns[1], state.child_states[2], result, target_count); + if (result.GetType().id() == LogicalTypeId::LIST) { + //! Shredded ARRAY Variant looks like: + //! LIST(STRUCT(typed_value , untyped_value_index UINTEGER)) + //! We need to transform this to: + //! LIST() + + auto &list_child = ListVector::GetEntry(result); + D_ASSERT(list_child.GetType().id() == LogicalTypeId::STRUCT); + D_ASSERT(StructType::GetChildCount(list_child.GetType()) == 2); + + auto &typed_value = *StructVector::GetEntries(list_child)[TYPED_VALUE_INDEX]; + auto list_res = Vector(LogicalType::LIST(typed_value.GetType())); + ListVector::SetListSize(list_res, ListVector::GetListSize(result)); + list_res.CopyBuffer(result); + ListVector::GetEntry(list_res).Reference(typed_value); + return res; + } + return res; + } + //! Fall back to unshredding + Vector intermediate(LogicalType::VARIANT(), target_count); + idx_t scan_count; + if (IsShredded()) { + auto unshredding_intermediate = CreateUnshreddingIntermediate(target_count); + auto &child_vectors = StructVector::GetEntries(unshredding_intermediate); + + callback(*sub_columns[0], state.child_states[1], *child_vectors[0], target_count); + callback(*sub_columns[1], state.child_states[2], *child_vectors[1], target_count); + scan_count = callback(*validity, state.child_states[0], unshredding_intermediate, target_count); + + VariantColumnData::UnshredVariantData(unshredding_intermediate, intermediate, target_count); + } else { + scan_count = callback(*validity, state.child_states[0], intermediate, target_count); + callback(*sub_columns[0], state.child_states[1], intermediate, target_count); + } - VariantColumnData::UnshredVariantData(intermediate, result, target_count); + Vector extract_intermediate(LogicalType::VARIANT(), target_count); + vector components; + reference path_iter(state.storage_index.GetChildIndex(0)); + + while (true) { + auto ¤t = path_iter.get(); + auto &field_name = current.GetFieldName(); + components.emplace_back(field_name); + if (!current.HasChildren()) { + break; + } + path_iter = current.GetChildIndex(0); + } + VariantUtils::VariantExtract(intermediate, components, extract_intermediate, target_count); + + if (state.expression_state) { + auto &expression_state = *state.expression_state; + auto &executor = expression_state.executor; + + auto &input = expression_state.input; + auto &target = expression_state.target; + input.Reset(); + target.Reset(); + input.data[0].Reference(extract_intermediate); + input.SetCardinality(scan_count); + executor.Execute(input, target); + result.Reference(target.data[0]); + } else { + result.Reference(extract_intermediate); + } + return scan_count; + } else { + if (IsShredded()) { + auto intermediate = CreateUnshreddingIntermediate(target_count); + auto &child_vectors = StructVector::GetEntries(intermediate); + + callback(*sub_columns[0], state.child_states[1], *child_vectors[0], target_count); + callback(*sub_columns[1], state.child_states[2], *child_vectors[1], target_count); + auto scan_count = callback(*validity, state.child_states[0], intermediate, target_count); + + VariantColumnData::UnshredVariantData(intermediate, result, target_count); + return scan_count; + } + auto scan_count = callback(*validity, state.child_states[0], result, target_count); + callback(*sub_columns[0], state.child_states[1], result, target_count); return scan_count; } - auto scan_count = validity->Scan(transaction, vector_index, state.child_states[0], result, target_count); - sub_columns[0]->Scan(transaction, vector_index, state.child_states[1], result, target_count); - return scan_count; +} + +idx_t VariantColumnData::Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, + idx_t target_count) { + return ScanWithCallback(state, result, target_count, + [&](ColumnData &col, ColumnScanState &child_state, Vector &target_vector, idx_t count) { + return col.Scan(transaction, vector_index, child_state, target_vector, count); + }); } idx_t VariantColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t count, idx_t result_offset) { - auto scan_count = sub_columns[0]->ScanCount(state.child_states[1], result, count, result_offset); - return scan_count; + return ScanWithCallback(state, result, count, + [&](ColumnData &col, ColumnScanState &child_state, Vector &target_vector, idx_t count) { + return col.ScanCount(child_state, target_vector, count, result_offset); + }); } void VariantColumnData::Skip(ColumnScanState &state, idx_t count) { @@ -242,35 +453,73 @@ unique_ptr VariantColumnData::GetUpdateStatistics() { void VariantColumnData::FetchRow(TransactionData transaction, ColumnFetchState &state, const StorageIndex &storage_index, row_t row_id, Vector &result, idx_t result_idx) { - // insert any child states that are required - for (idx_t i = state.child_states.size(); i < sub_columns.size() + 1; i++) { - auto child_state = make_uniq(); - state.child_states.push_back(std::move(child_state)); + if (storage_index.IsPushdownExtract() && IsShredded()) { + StorageIndex struct_extract; + if (PushdownShreddedFieldExtract(storage_index.GetChildIndex(0), struct_extract)) { + //! Shredded field exists and is fully shredded, + //! add the storage index to create a pushed-down 'struct_extract' to get the leaf + sub_columns[1]->FetchRow(transaction, state, struct_extract, row_id, result, result_idx); + return; + } } - + Vector variant_vec(LogicalType::VARIANT(), result_idx + 1); + validity->FetchRow(transaction, state, storage_index, row_id, variant_vec, result_idx); if (IsShredded()) { auto intermediate = CreateUnshreddingIntermediate(result_idx + 1); auto &child_vectors = StructVector::GetEntries(intermediate); // fetch the validity state - validity->FetchRow(transaction, *state.child_states[0], storage_index, row_id, result, result_idx); // fetch the sub-column states + StorageIndex empty(0); for (idx_t i = 0; i < sub_columns.size(); i++) { - sub_columns[i]->FetchRow(transaction, *state.child_states[i + 1], storage_index, row_id, *child_vectors[i], - result_idx); + sub_columns[i]->FetchRow(transaction, state, empty, row_id, *child_vectors[i], result_idx); } if (result_idx) { intermediate.SetValue(0, intermediate.GetValue(result_idx)); } - //! FIXME: adjust UnshredVariantData so we can write the value in place into 'result' directly. - Vector unshredded(result.GetType(), 1); + //! FIXME: adjust UnshredVariantData so we can write the value in place directly. + Vector unshredded(variant_vec.GetType(), 1); VariantColumnData::UnshredVariantData(intermediate, unshredded, 1); - result.SetValue(result_idx, unshredded.GetValue(0)); + variant_vec.SetValue(0, unshredded.GetValue(0)); + } else { + sub_columns[0]->FetchRow(transaction, state, storage_index, row_id, variant_vec, result_idx); + if (result_idx) { + variant_vec.SetValue(0, variant_vec.GetValue(result_idx)); + } + } + + if (!storage_index.IsPushdownExtract()) { + //! No extract required + D_ASSERT(result.GetType().id() == LogicalTypeId::VARIANT); + result.SetValue(result_idx, variant_vec.GetValue(0)); return; } - validity->FetchRow(transaction, *state.child_states[0], storage_index, row_id, result, result_idx); - sub_columns[0]->FetchRow(transaction, *state.child_states[1], storage_index, row_id, result, result_idx); + Vector extracted_variant(variant_vec.GetType(), 1); + vector components; + reference path_iter(storage_index.GetChildIndex(0)); + + while (true) { + auto ¤t = path_iter.get(); + auto &field_name = current.GetFieldName(); + components.emplace_back(field_name); + if (!current.HasChildren()) { + break; + } + path_iter = current.GetChildIndex(0); + } + VariantUtils::VariantExtract(variant_vec, components, extracted_variant, 1); + + if (result.GetType().id() == LogicalTypeId::VARIANT) { + //! No cast required + result.SetValue(result_idx, extracted_variant.GetValue(0)); + return; + } + + //! Need to perform the cast here as well + auto context = transaction.transaction->context.lock(); + auto fetched_row = extracted_variant.GetValue(0).CastAs(*context, result.GetType()); + result.SetValue(result_idx, fetched_row); } void VariantColumnData::VisitBlockIds(BlockIdVisitor &visitor) const { @@ -345,11 +594,12 @@ struct VariantColumnCheckpointState : public ColumnCheckpointState { PersistentColumnData ToPersistentData() override { PersistentColumnData data(original_column.type); - auto &variant_column_data = GetResultColumn().Cast(); if (child_states.size() == 2) { - D_ASSERT(variant_column_data.sub_columns.size() == 2); - D_ASSERT(variant_column_data.sub_columns[1]->type.id() == LogicalTypeId::STRUCT); - data.SetVariantShreddedType(variant_column_data.sub_columns[1]->type); + //! Use the type of the column data we used to create the Checkpoint + //! This will either be a pointer to shredded_data[1] if we decided to shred + //! Or to the existing shredded column data if we didn't decide to reshred + auto &shredded_state = child_states[1]; + data.extra_data = make_uniq(shredded_state->original_column.type); } data.child_columns.push_back(validity_state->ToPersistentData()); for (auto &child_state : child_states) { @@ -452,27 +702,28 @@ static bool EnableShredding(int64_t minimum_size, idx_t current_size) { } unique_ptr VariantColumnData::Checkpoint(const RowGroup &row_group, - ColumnCheckpointInfo &checkpoint_info) { + ColumnCheckpointInfo &checkpoint_info, + const BaseStatistics &old_stats) { auto &partial_block_manager = checkpoint_info.GetPartialBlockManager(); auto checkpoint_state = make_uniq(row_group, *this, partial_block_manager); - checkpoint_state->validity_state = validity->Checkpoint(row_group, checkpoint_info); + checkpoint_state->validity_state = validity->Checkpoint(row_group, checkpoint_info, old_stats); auto &table_info = row_group.GetTableInfo(); auto &db = table_info.GetDB(); - auto &config_options = DBConfig::Get(db).options; + auto &config = DBConfig::Get(db); bool should_shred = true; if (!HasAnyChanges()) { should_shred = false; } - if (!EnableShredding(config_options.variant_minimum_shredding_size, row_group.count.load())) { + if (!EnableShredding(Settings::Get(config), count.load())) { should_shred = false; } LogicalType shredded_type; if (should_shred) { - if (config_options.force_variant_shredding.id() != LogicalTypeId::INVALID) { - shredded_type = config_options.force_variant_shredding; + if (config.options.force_variant_shredding.id() != LogicalTypeId::INVALID) { + shredded_type = config.options.force_variant_shredding; } else { shredded_type = GetShreddedType(); } @@ -485,8 +736,11 @@ unique_ptr VariantColumnData::Checkpoint(const RowGroup & } if (!should_shred) { - for (idx_t i = 0; i < sub_columns.size(); i++) { - checkpoint_state->child_states.push_back(sub_columns[i]->Checkpoint(row_group, checkpoint_info)); + checkpoint_state->child_states.push_back( + sub_columns[0]->Checkpoint(row_group, checkpoint_info, VariantStats::GetUnshreddedStats(old_stats))); + if (sub_columns.size() > 1) { + checkpoint_state->child_states.push_back( + sub_columns[1]->Checkpoint(row_group, checkpoint_info, VariantStats::GetShreddedStats(old_stats))); } return std::move(checkpoint_state); } @@ -499,8 +753,10 @@ unique_ptr VariantColumnData::Checkpoint(const RowGroup & auto &shredded = checkpoint_state->shredded_data[1]; //! Now checkpoint the shredded data - checkpoint_state->child_states.push_back(unshredded->Checkpoint(row_group, checkpoint_info)); - checkpoint_state->child_states.push_back(shredded->Checkpoint(row_group, checkpoint_info)); + checkpoint_state->child_states.push_back( + unshredded->Checkpoint(row_group, checkpoint_info, VariantStats::GetUnshreddedStats(column_stats))); + checkpoint_state->child_states.push_back( + shredded->Checkpoint(row_group, checkpoint_info, VariantStats::GetShreddedStats(column_stats))); return std::move(checkpoint_state); } @@ -534,7 +790,8 @@ bool VariantColumnData::HasAnyChanges() const { PersistentColumnData VariantColumnData::Serialize() { PersistentColumnData persistent_data(type); if (IsShredded()) { - persistent_data.SetVariantShreddedType(sub_columns[1]->type); + // Set the extra data to indicate that this is shredded data + persistent_data.extra_data = make_uniq(sub_columns[1]->type); } persistent_data.child_columns.push_back(validity->Serialize()); for (idx_t i = 0; i < sub_columns.size(); i++) { @@ -552,7 +809,10 @@ void VariantColumnData::InitializeColumn(PersistentColumnData &column_data, Base auto &unshredded_stats = VariantStats::GetUnshreddedStats(target_stats); sub_columns[0]->InitializeColumn(column_data.child_columns[1], unshredded_stats); - auto &shredded_type = column_data.variant_shredded_type; + // TODO: + D_ASSERT(column_data.extra_data); + auto &variant_extra_data = column_data.extra_data->Cast(); + auto &shredded_type = variant_extra_data.logical_type; if (!IsShredded()) { VariantStats::SetShreddedStats(target_stats, BaseStatistics::CreateEmpty(shredded_type)); sub_columns.push_back(ColumnData::CreateColumn(block_manager, info, 2, shredded_type, GetDataType(), this)); diff --git a/src/duckdb/src/storage/table_index_list.cpp b/src/duckdb/src/storage/table_index_list.cpp index 186db5143..734106e82 100644 --- a/src/duckdb/src/storage/table_index_list.cpp +++ b/src/duckdb/src/storage/table_index_list.cpp @@ -2,6 +2,8 @@ #include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" #include "duckdb/common/types/conflict_manager.hpp" +#include "duckdb/execution/index/art/art.hpp" +#include "duckdb/storage/table/append_state.hpp" #include "duckdb/execution/index/index_type_set.hpp" #include "duckdb/execution/index/unbound_index.hpp" #include "duckdb/main/config.hpp" @@ -21,6 +23,68 @@ IndexEntry::IndexEntry(unique_ptr index_p) : index(std::move(index_p)) { } } +template +TableIndexIterationHelper::TableIndexIterationHelper(mutex &index_lock, + const vector> &index_entries) + : lock(index_lock), index_entries(index_entries) { +} + +template +TableIndexIterationHelper::TableIndexIterator::TableIndexIterator( + optional_ptr>> index_entries_p) + : index_entries(index_entries_p) { + if (index_entries) { + if (index_entries->empty()) { + index_entries = nullptr; + } else { + index = 0; + } + } +} + +template +typename TableIndexIterationHelper::TableIndexIterator & +TableIndexIterationHelper::TableIndexIterator::operator++() { + if (index_entries) { + auto next_index = index.GetIndex() + 1; + if (next_index >= index_entries->size()) { + // reached the end + index = optional_idx(); + index_entries = nullptr; + } else { + // next index + index = next_index; + } + } + return *this; +} + +template +bool TableIndexIterationHelper::TableIndexIterator::operator!=(const TableIndexIterator &other) const { + return index != other.index || index_entries != other.index_entries; +} + +template <> +IndexEntry &TableIndexIterationHelper::TableIndexIterator::operator*() const { + return *index_entries->at(index.GetIndex()); +} + +template <> +Index &TableIndexIterationHelper::TableIndexIterator::operator*() const { + return *index_entries->at(index.GetIndex())->index; +} + +TableIndexIterationHelper TableIndexList::IndexEntries() const { + return TableIndexIterationHelper(index_entries_lock, index_entries); +} + +TableIndexIterationHelper TableIndexList::Indexes() const { + return TableIndexIterationHelper(index_entries_lock, index_entries); +} + +template class TableIndexIterationHelper; +template class TableIndexIterationHelper; + void TableIndexList::AddIndex(unique_ptr index) { D_ASSERT(index); lock_guard lock(index_entries_lock); @@ -118,8 +182,7 @@ void TableIndexList::Bind(ClientContext &context, DataTableInfo &table_info, con } } if (!index_entry) { - // We bound all indexes. - D_ASSERT(unbound_count == 0); + // We bound all indexes. (of this type) break; } if (index_entry->bind_state == IndexBindState::BINDING) { @@ -249,125 +312,66 @@ unordered_set TableIndexList::GetRequiredColumns() { return column_ids; } -vector TableIndexList::SerializeToDisk(QueryContext context, const IndexSerializationInfo &info) { +IndexSerializationResult TableIndexList::SerializeToDisk(QueryContext context, const IndexSerializationInfo &info) { lock_guard lock(index_entries_lock); - vector infos; + + IndexSerializationResult result; + + idx_t bound_count = 0; + for (auto &entry : index_entries) { + if (entry->index->IsBound()) { + bound_count++; + } + } + result.bound_infos.reserve(bound_count); for (auto &entry : index_entries) { auto &index = *entry->index; if (!index.IsBound()) { - auto storage_info = index.Cast().GetStorageInfo(); - D_ASSERT(!storage_info.name.empty()); - infos.push_back(storage_info); + // Unbound: reference existing storage info + auto &unbound_index = index.Cast(); + D_ASSERT(!unbound_index.GetStorageInfo().name.empty()); + result.ordered_infos.push_back(unbound_index.GetStorageInfo()); continue; } - // serialize the index to disk + // Bound: move new storage info into bound_infos, then reference it auto &bound_index = index.Cast(); auto storage_info = bound_index.SerializeToDisk(context, info.options); D_ASSERT(storage_info.IsValid() && !storage_info.name.empty()); - infos.push_back(storage_info); + result.bound_infos.push_back(std::move(storage_info)); + result.ordered_infos.push_back(result.bound_infos.back()); } - return infos; + + return result; } -void TableIndexList::MergeCheckpointDeltas(DataTable &storage, transaction_t checkpoint_id) { +void TableIndexList::MergeCheckpointDeltas(transaction_t checkpoint_id) { lock_guard lock(index_entries_lock); for (auto &entry : index_entries) { - // merge any data appended to the index while the checkpoint was running + // Merge any data appended to the index while the checkpoint was running. auto &index = *entry->index; if (!index.IsBound()) { continue; } lock_guard guard(entry->lock); auto &bound_index = index.Cast(); - vector> delta_indexes; - vector delta_index_is_delete; + auto &art = bound_index.Cast(); + if (entry->removed_data_during_checkpoint) { - delta_indexes.push_back(*entry->removed_data_during_checkpoint); - delta_index_is_delete.push_back(true); + art.RemovalMerge(*entry->removed_data_during_checkpoint); } if (entry->added_data_during_checkpoint) { - delta_indexes.push_back(*entry->added_data_during_checkpoint); - delta_index_is_delete.push_back(false); - } - for (idx_t i = 0; i < delta_indexes.size(); i++) { - auto &delta_index = delta_indexes[i].get(); - auto is_delete = delta_index_is_delete[i]; - // FIXME: this should use an optimized (removal) merge instead of doing fetches in the base table - // fetch all row-ids to delete - auto &art = delta_index.Cast(); - auto scan_state = art.InitializeFullScan(); - set all_row_ids; - art.Scan(*scan_state, NumericLimits::Maximum(), all_row_ids); - - // FIXME: this is mostly copied over from RowGroupCollection::RemoveFromIndexes, but we shouldn't be doing - // this anyway... - if (!all_row_ids.empty()) { - // in a loop fetch the - Vector row_identifiers(LogicalType::BIGINT); - auto row_ids = FlatVector::GetData(row_identifiers); - idx_t count = 0; - - auto indexed_column_id_set = bound_index.GetColumnIdSet(); - vector column_ids; - for (auto &col : indexed_column_id_set) { - column_ids.emplace_back(col); - } - sort(column_ids.begin(), column_ids.end()); - - auto types = storage.GetTypes(); - vector column_types; - for (auto &col : column_ids) { - column_types.push_back(types[col.GetPrimaryIndex()]); - } - - DataChunk fetch_chunk; - fetch_chunk.Initialize(Allocator::DefaultAllocator(), column_types); - - ColumnFetchState state; - state.fetch_type = FetchType::FORCE_FETCH; - - DataChunk result_chunk; - auto fetched_columns = vector(types.size(), false); - result_chunk.Initialize(Allocator::DefaultAllocator(), types, fetched_columns); - // Now set all to-be-fetched columns. - for (auto &col : indexed_column_id_set) { - fetched_columns[col] = true; - } - auto last_row_id = *all_row_ids.rbegin(); - for (auto &row_id : all_row_ids) { - row_ids[count++] = row_id; - if (row_id == last_row_id || count == STANDARD_VECTOR_SIZE) { - fetch_chunk.Reset(); - storage.FetchCommitted(fetch_chunk, column_ids, row_identifiers, count, state); - - // Reference the necessary columns of the fetch_chunk. - idx_t fetch_idx = 0; - for (idx_t j = 0; j < types.size(); j++) { - if (fetched_columns[j]) { - result_chunk.data[j].Reference(fetch_chunk.data[fetch_idx++]); - continue; - } - result_chunk.data[j].Reference(Value(types[j])); - } - result_chunk.SetCardinality(fetch_chunk); - if (is_delete) { - auto delete_count = bound_index.TryDelete(result_chunk, row_identifiers); - if (delete_count != result_chunk.size()) { - throw InternalException("Failed to remove all rows while merging checkpoint deltas - " - "this signifies a bug or broken index\nChunk: %s", - result_chunk.ToString()); - } - } else { - auto error = bound_index.Append(result_chunk, row_identifiers); - if (error.HasError()) { - throw InternalException("Failed to append while merging checkpoint deltas - this " - "signifies a bug or broken index: %s", - error.Message()); - } - } - count = 0; - } - } + // NOTE: we insert duplicates here (IndexAppendMode::INSERT_DUPLICATES) + // this is necessary due to the way that data is inserted into indexes during transaction commit + // essentially we always FIRST insert data into the index, THEN remove data + // even if the data was logically removed first + // i.e. if we have a transaction like: DELETE FROM tbl WHERE i=42; INSERT INTO tbl VALUES (42); + // we will FIRST insert 42, THEN delete 42 from the index + // We plan to change this in the future - see https://github.com/duckdblabs/duckdb-internal/issues/6886 + auto error = art.InsertMerge(*entry->added_data_during_checkpoint, IndexAppendMode::INSERT_DUPLICATES); + if (error.HasError()) { + throw InternalException("Failed to append while merging checkpoint deltas - this " + "signifies a bug or broken index: %s", + error.Message()); } } entry->removed_data_during_checkpoint.reset(); diff --git a/src/duckdb/src/storage/temporary_file_manager.cpp b/src/duckdb/src/storage/temporary_file_manager.cpp index 057f6db29..d62ab728c 100644 --- a/src/duckdb/src/storage/temporary_file_manager.cpp +++ b/src/duckdb/src/storage/temporary_file_manager.cpp @@ -4,6 +4,7 @@ #include "duckdb/parallel/task_scheduler.hpp" #include "duckdb/storage/buffer/temporary_file_information.hpp" #include "duckdb/main/database.hpp" +#include "duckdb/main/settings.hpp" #include "duckdb/common/encryption_functions.hpp" #include "zstd.h" @@ -639,7 +640,7 @@ void TemporaryFileManager::DecreaseSizeOnDisk(idx_t bytes) { } bool TemporaryFileManager::IsEncrypted() const { - return db.config.options.temp_file_encryption; + return Settings::Get(db); } unique_ptr TemporaryFileManager::ReadTemporaryBuffer(QueryContext context, block_id_t id, diff --git a/src/duckdb/src/storage/wal_replay.cpp b/src/duckdb/src/storage/wal_replay.cpp index b972882b4..057aec661 100644 --- a/src/duckdb/src/storage/wal_replay.cpp +++ b/src/duckdb/src/storage/wal_replay.cpp @@ -7,6 +7,7 @@ #include "duckdb/common/serializer/binary_deserializer.hpp" #include "duckdb/common/serializer/buffered_file_reader.hpp" #include "duckdb/common/serializer/memory_stream.hpp" +#include "duckdb/common/enums/checkpoint_abort.hpp" #include "duckdb/execution/index/art/art.hpp" #include "duckdb/execution/index/index_type_set.hpp" #include "duckdb/main/attached_database.hpp" @@ -27,6 +28,7 @@ #include "duckdb/storage/table/delete_state.hpp" #include "duckdb/storage/write_ahead_log.hpp" #include "duckdb/transaction/meta_transaction.hpp" +#include "duckdb/transaction/duck_transaction.hpp" #include "duckdb/main/client_data.hpp" #include "duckdb/main/settings.hpp" @@ -34,7 +36,8 @@ namespace duckdb { class ReplayState { public: - ReplayState(AttachedDatabase &db, ClientContext &context) : db(db), context(context), catalog(db.GetCatalog()) { + ReplayState(AttachedDatabase &db, ClientContext &context, WALReplayState replay_state_p) + : db(db), context(context), catalog(db.GetCatalog()), replay_state(replay_state_p) { } AttachedDatabase &db; @@ -46,6 +49,7 @@ class ReplayState { optional_idx current_position; optional_idx checkpoint_position; optional_idx expected_checkpoint_id; + WALReplayState replay_state; struct ReplayIndexInfo { ReplayIndexInfo(TableIndexList &index_list, unique_ptr index, const string &table_schema, @@ -126,27 +130,33 @@ class WriteAheadLogDeserializer { auto offset = stream.CurrentOffset(); auto file_size = stream.FileSize(); - EncryptionNonce nonce; + EncryptionNonce nonce(state_p.db.GetStorageManager().GetCipher(), + state_p.db.GetStorageManager().GetEncryptionVersion()); EncryptionTag tag; - if (offset + nonce.size() + ciphertext_size + tag.size() > file_size) { - throw SerializationException( - "Corrupt Encrypted WAL file: entry size exceeded remaining data in file at byte position %llu " - "(found entry with size %llu bytes, file size %llu bytes)", - offset, size, file_size); - } - stream.ReadData(nonce.data(), nonce.size()); auto &keys = EncryptionKeyManager::Get(state_p.db.GetDatabase()); auto &catalog = state_p.db.GetCatalog().Cast(); auto derived_key = keys.GetKey(catalog.GetEncryptionKeyId()); - + auto metadata = make_uniq(state_p.db.GetStorageManager().GetCipher(), + MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, + state_p.db.GetStorageManager().GetEncryptionVersion()); //! initialize the decryption - auto encryption_state = database.GetEncryptionUtil()->CreateEncryptionState( - state_p.db.GetStorageManager().GetCipher(), MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); - encryption_state->InitializeDecryption(nonce.data(), nonce.size(), derived_key, - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + auto encryption_state = + database.GetEncryptionUtil(state_p.db.IsReadOnly())->CreateEncryptionState(std::move(metadata)); + encryption_state->InitializeDecryption(nonce, derived_key); + + if (encryption_state->GetCipher() == EncryptionTypes::CipherType::CTR) { + tag.SetSize(0); + } + + if (offset + nonce.size() + ciphertext_size + tag.size() > file_size) { + throw SerializationException( + "Corrupt Encrypted WAL file: entry size exceeded remaining data in file at byte position %llu " + "(found entry with size %llu bytes, file size %llu bytes)", + offset, size, file_size); + } //! Allocate a decryption buffer auto buffer = unique_ptr(new data_t[ciphertext_size]); @@ -155,10 +165,14 @@ class WriteAheadLogDeserializer { stream.ReadData(buffer.get(), ciphertext_size); encryption_state->Process(buffer.get(), ciphertext_size, buffer.get(), ciphertext_size); - //! read and verify the stored tag - stream.ReadData(tag.data(), tag.size()); - - encryption_state->Finalize(buffer.get(), ciphertext_size, tag.data(), tag.size()); + if (encryption_state->GetCipher() == EncryptionTypes::CipherType::GCM) { + //! read and verify the stored tag + stream.ReadData(tag.data(), tag.size()); + D_ASSERT(!tag.IsAllZeros()); + encryption_state->Finalize(buffer.get(), ciphertext_size, tag.data(), tag.size()); + } else { + encryption_state->Finalize(buffer.get(), ciphertext_size, nullptr, 0); + } //! read the stored checksum auto stored_checksum = Load(buffer.get()); @@ -306,7 +320,7 @@ unique_ptr WriteAheadLog::ReplayInternal(QueryContext context, St auto &config = DBConfig::GetConfig(database.GetDatabase()); // first deserialize the WAL to look for a checkpoint flag // if there is a checkpoint flag, we might have already flushed the contents of the WAL to disk - ReplayState checkpoint_state(database, *con.context); + ReplayState checkpoint_state(database, *con.context, replay_state); try { idx_t replay_entry_count = 0; while (true) { @@ -402,7 +416,7 @@ unique_ptr WriteAheadLog::ReplayInternal(QueryContext context, St BufferedFileReader checkpoint_reader(FileSystem::Get(database), std::move(checkpoint_handle)); // skip over the version entry - ReplayState checkpoint_replay_state(database, *con.context); + ReplayState checkpoint_replay_state(database, *con.context, WALReplayState::CHECKPOINT_WAL); auto deserializer = WriteAheadLogDeserializer::GetEntryDeserializer(checkpoint_replay_state, checkpoint_reader, true); deserializer.ReplayEntry(); @@ -417,8 +431,7 @@ unique_ptr WriteAheadLog::ReplayInternal(QueryContext context, St checkpoint_reader.FileSize()); } - auto debug_checkpoint_abort = - DBConfig::GetSetting(storage_manager.GetDatabase()); + auto debug_checkpoint_abort = Settings::Get(storage_manager.GetDatabase()); // move over the recovery WAL over the main WAL recovery_handle->Sync(); @@ -452,7 +465,7 @@ unique_ptr WriteAheadLog::ReplayInternal(QueryContext context, St } // we need to recover from the WAL: actually set up the replay state - ReplayState state(database, *con.context); + ReplayState state(database, *con.context, replay_state); // reset the reader - we are going to read the WAL from the beginning again reader.Reset(); @@ -637,6 +650,12 @@ void WriteAheadLogDeserializer::ReplayVersion() { state.expected_checkpoint_id = expected_checkpoint_iteration; return; } + if (state.replay_state == WALReplayState::CHECKPOINT_WAL && + wal_checkpoint_iteration == expected_checkpoint_iteration + 1) { + // if we are recovering from a checkpoint WAL, the checkpoint iteration is possibly one higher + // (depending on when the crash happened) + return; + } ThrowVersionError(wal_checkpoint_iteration, expected_checkpoint_iteration); } } @@ -765,7 +784,7 @@ void WriteAheadLogDeserializer::ReplayAlter() { } auto &storage = table.GetStorage(); - CreateIndexInput input(TableIOManager::Get(storage), storage.db, IndexConstraintType::PRIMARY, + CreateIndexInput input(context, TableIOManager::Get(storage), storage.db, IndexConstraintType::PRIMARY, index_storage_info.name, column_ids, unbound_expressions, index_storage_info, index_storage_info.options); @@ -1059,10 +1078,39 @@ void WriteAheadLogDeserializer::ReplayRowGroupData() { } auto &storage = state.current_table->GetStorage(); auto &table_info = storage.GetDataTableInfo(); - RowGroupCollection new_row_groups(table_info, table_info->GetIOManager(), storage.GetTypes(), 0); + auto base_row = storage.GetTotalRows(); + RowGroupCollection new_row_groups(table_info, table_info->GetIOManager(), storage.GetTypes(), base_row); new_row_groups.Initialize(data); - TableIndexList index_list; - storage.MergeStorage(new_row_groups, index_list, nullptr); + + // if we have any indexes - scan the row groups and add data to the indexes + auto &indexes = table_info->GetIndexes(); + if (!indexes.Empty()) { + auto &transaction = DuckTransaction::Get(context, db); + // we have indexes - append + vector column_ids; + for (auto &col : state.current_table->GetColumns().Physical()) { + column_ids.emplace_back(col.StorageOid()); + } + Vector row_id_vector(LogicalType::ROW_TYPE, STANDARD_VECTOR_SIZE); + auto row_ids = FlatVector::GetData(row_id_vector); + auto current_row_id = storage.GetTotalRows(); + for (auto &chunk : new_row_groups.Chunks(transaction, column_ids)) { + for (idx_t r = 0; r < chunk.size(); r++) { + row_ids[r] = NumericCast(current_row_id + r); + } + current_row_id += chunk.size(); + for (auto &index : indexes.Indexes()) { + if (!index.IsBound()) { + auto &unbound_index = index.Cast(); + unbound_index.BufferChunk(chunk, row_id_vector, column_ids, BufferedIndexReplay::INSERT_ENTRY); + continue; + } + auto &bound_index = index.Cast(); + bound_index.Append(chunk, row_id_vector); + } + } + } + storage.MergeStorage(new_row_groups, nullptr); } void WriteAheadLogDeserializer::ReplayDelete() { diff --git a/src/duckdb/src/storage/write_ahead_log.cpp b/src/duckdb/src/storage/write_ahead_log.cpp index d15f85fe1..64d42a693 100644 --- a/src/duckdb/src/storage/write_ahead_log.cpp +++ b/src/duckdb/src/storage/write_ahead_log.cpp @@ -32,6 +32,7 @@ WriteAheadLog::WriteAheadLog(StorageManager &storage_manager, const string &wal_ : storage_manager(storage_manager), wal_path(wal_path), init_state(init_state), checkpoint_iteration(checkpoint_iteration) { storage_manager.SetWALSize(wal_size); + storage_manager.ResetWALEntriesCount(); } WriteAheadLog::~WriteAheadLog() { @@ -138,15 +139,17 @@ class ChecksumWriter : public WriteStream { auto &db = wal.GetDatabase(); auto &keys = EncryptionKeyManager::Get(db.GetDatabase()); - - auto encryption_state = db.GetDatabase().GetEncryptionUtil()->CreateEncryptionState( - db.GetStorageManager().GetCipher(), MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + auto metadata = make_uniq(db.GetStorageManager().GetCipher(), + MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH, + EncryptionTypes::EncryptionVersion::V0_1); + auto encryption_state = + db.GetDatabase().GetEncryptionUtil(db.IsReadOnly())->CreateEncryptionState(std::move(metadata)); // temp buffer const idx_t ciphertext_size = size + sizeof(uint64_t); std::unique_ptr temp_buf(new uint8_t[ciphertext_size]); - EncryptionNonce nonce; + EncryptionNonce nonce(db.GetStorageManager().GetCipher(), db.GetStorageManager().GetEncryptionVersion()); EncryptionTag tag; // generate nonce @@ -161,8 +164,7 @@ class ChecksumWriter : public WriteStream { memcpy(temp_buf.get() + sizeof(checksum), memory_stream.GetData(), memory_stream.GetPosition()); //! encrypt the temp buf - encryption_state->InitializeEncryption(nonce.data(), nonce.size(), keys.GetKey(encryption_key_id), - MainHeader::DEFAULT_ENCRYPTION_KEY_LENGTH); + encryption_state->InitializeEncryption(nonce, keys.GetKey(encryption_key_id)); encryption_state->Process(temp_buf.get(), ciphertext_size, temp_buf.get(), ciphertext_size); //! calculate the tag (for GCM) @@ -172,12 +174,19 @@ class ChecksumWriter : public WriteStream { stream->WriteData(temp_buf.get(), ciphertext_size); // Write the tag to the stream - stream->WriteData(tag.data(), tag.size()); + if (encryption_state->GetCipher() == EncryptionTypes::CipherType::GCM) { + D_ASSERT(!tag.IsAllZeros()); + stream->WriteData(tag.data(), tag.size()); + } // rewind the buffer memory_stream.Rewind(); } + WriteAheadLog &GetWAL() { + return wal; + } + private: WriteAheadLog &wal; optional_ptr stream; @@ -200,6 +209,7 @@ class WriteAheadLogSerializer { void End() { serializer.End(); checksum_writer.Flush(); + checksum_writer.GetWAL().IncrementWALEntriesCount(); } template @@ -364,7 +374,7 @@ void SerializeIndex(AttachedDatabase &db, WriteAheadLogSerializer &serializer, T options["v1_0_0_storage"] = v1_0_0_storage; } - list.Scan([&](Index &index) { + for (auto &index : list.Indexes()) { if (name == index.GetIndexName()) { // We never write an unbound index to the WAL. D_ASSERT(index.IsBound()); @@ -376,10 +386,9 @@ void SerializeIndex(AttachedDatabase &db, WriteAheadLogSerializer &serializer, T list.WriteElement(buffer.buffer_ptr, buffer.allocation_size); } }); - return true; + break; } - return false; - }); + } } void WriteAheadLog::WriteCreateIndex(const IndexCatalogEntry &entry) { @@ -534,4 +543,8 @@ void WriteAheadLog::Flush() { storage_manager.SetWALSize(writer->GetFileSize()); } +void WriteAheadLog::IncrementWALEntriesCount() { + storage_manager.IncrementWALEntriesCount(); +} + } // namespace duckdb diff --git a/src/duckdb/src/transaction/commit_state.cpp b/src/duckdb/src/transaction/commit_state.cpp index be4806985..a3e0c4bee 100644 --- a/src/duckdb/src/transaction/commit_state.cpp +++ b/src/duckdb/src/transaction/commit_state.cpp @@ -213,6 +213,7 @@ void CommitState::CommitEntryDrop(CatalogEntry &entry, data_ptr_t dataptr) { case CatalogType::COPY_FUNCTION_ENTRY: case CatalogType::PRAGMA_FUNCTION_ENTRY: case CatalogType::COLLATION_ENTRY: + case CatalogType::COORDINATE_SYSTEM_ENTRY: case CatalogType::DEPENDENCY_ENTRY: case CatalogType::SECRET_ENTRY: case CatalogType::SECRET_TYPE_ENTRY: diff --git a/src/duckdb/src/transaction/duck_transaction.cpp b/src/duckdb/src/transaction/duck_transaction.cpp index d4c73c5cf..15c44fa72 100644 --- a/src/duckdb/src/transaction/duck_transaction.cpp +++ b/src/duckdb/src/transaction/duck_transaction.cpp @@ -200,6 +200,10 @@ bool DuckTransaction::ShouldWriteToWAL(AttachedDatabase &db) { if (db.IsSystem()) { return false; } + if (db.GetRecoveryMode() == RecoveryMode::NO_WAL_WRITES) { + // WAL writes are explicitly disabled + return false; + } auto &storage_manager = db.GetStorageManager(); if (!storage_manager.HasWAL()) { return false; diff --git a/src/duckdb/src/transaction/duck_transaction_manager.cpp b/src/duckdb/src/transaction/duck_transaction_manager.cpp index 29d2fbde3..901dd9b74 100644 --- a/src/duckdb/src/transaction/duck_transaction_manager.cpp +++ b/src/duckdb/src/transaction/duck_transaction_manager.cpp @@ -94,10 +94,6 @@ ActiveCheckpointWrapper::ActiveCheckpointWrapper(DuckTransactionManager &manager : manager(manager), is_cleared(false) { } -ActiveCheckpointWrapper::~ActiveCheckpointWrapper() { - Clear(); -} - void ActiveCheckpointWrapper::Clear() { if (is_cleared) { return; @@ -155,7 +151,7 @@ DuckTransactionManager::CanCheckpoint(DuckTransaction &transaction, unique_ptr(db.GetDatabase())) { + if (Settings::Get(db.GetDatabase())) { return CheckpointDecision("checkpointing on commit disabled through configuration"); } // try to lock the checkpoint lock @@ -164,6 +160,12 @@ DuckTransactionManager::CanCheckpoint(DuckTransaction &transaction, unique_ptr c_lock(cleanup_lock); + while (true) { + unique_ptr top_cleanup_info; + { + lock_guard q_lock(cleanup_queue_lock); + if (cleanup_queue.empty()) { + // all transactions have been cleaned up - done + return; + } + top_cleanup_info = std::move(cleanup_queue.front()); + cleanup_queue.pop(); + } + if (top_cleanup_info) { + top_cleanup_info->Cleanup(); + } + } +} + ErrorData DuckTransactionManager::CommitTransaction(ClientContext &context, Transaction &transaction_p) { auto &transaction = transaction_p.Cast(); unique_lock t_lock(transaction_lock); @@ -298,24 +319,54 @@ ErrorData DuckTransactionManager::CommitTransaction(ClientContext &context, Tran ErrorData error; unique_ptr> held_wal_lock; unique_ptr commit_state; - if (!checkpoint_decision.can_checkpoint && transaction.ShouldWriteToWAL(db)) { + bool skip_wal_write_due_to_checkpoint = false; + if (checkpoint_decision.can_checkpoint) { + // we can perform an automatic checkpoint + // we have two options: + // either we write to the WAL, in which case we can perform concurrent commits while running + // OR we skip writing to the WAL, in which case we cannot perform concurrent commits + // the reason for this is that if we don't write this transactions' changes to the WAL + // any failure during checkpoint will cause this transactions' changes to be lost, + // while later concurrent commits will not be + // this can cause undefined state, as those commits were made assuming this one was already committed + if (undo_properties.estimated_size >= Settings::Get(context)) { + skip_wal_write_due_to_checkpoint = true; + } + } + bool should_write_to_wal = transaction.ShouldWriteToWAL(db); + if (should_write_to_wal) { auto &storage_manager = db.GetStorageManager().Cast(); - // if we are committing changes and we are not checkpointing, we need to write to the WAL + // if we are committing changes and we are not doing a "checkpoint instead of WAL write" + // we need to write to the WAL to make the changes durable // since WAL writes can take a long time - we grab the WAL lock here and unlock the transaction lock // read-only transactions can bypass this branch and start/commit while the WAL write is happening // unlock the transaction lock while we write to the WAL + // note: we can only drop the transaction lock if we are NOT checkpointing + // if we are checkpointing, we have already made certain decisions (e.g. the CheckpointType) t_lock.unlock(); // grab the WAL lock and hold it until the entire commit is finished held_wal_lock = storage_manager.GetWALLock(); // Commit the changes to the WAL. - if (db.GetRecoveryMode() == RecoveryMode::DEFAULT) { + if (!skip_wal_write_due_to_checkpoint) { error = transaction.WriteToWAL(context, db, commit_state); } // after we finish writing to the WAL we grab the transaction lock again t_lock.lock(); } + if (!error.HasError() && checkpoint_decision.can_checkpoint) { + // now that we have the transaction lock again, new transactions can't start + // figure out the checkpoint type now + checkpoint_decision = GetCheckpointType(transaction, undo_properties); + if (should_write_to_wal && skip_wal_write_due_to_checkpoint && !checkpoint_decision.can_checkpoint) { + // we have not written to the WAL but we have now realized we can't checkpoint after all + // in order to commit we need backpeddle and write to the WAL after all + D_ASSERT(held_wal_lock); + error = transaction.WriteToWAL(context, db, commit_state); + skip_wal_write_due_to_checkpoint = false; + } + } // in-memory databases don't have a WAL - we estimate how large their changeset is based on the undo properties if (!db.IsSystem()) { auto &storage_manager = db.GetStorageManager(); @@ -362,7 +413,8 @@ ErrorData DuckTransactionManager::CommitTransaction(ClientContext &context, Tran OnCommitCheckpointDecision(checkpoint_decision, transaction); if (!checkpoint_decision.can_checkpoint && lock) { - // we won't checkpoint after all: unlock the checkpoint lock again + // we won't checkpoint after all due to an error during commit: unlock the checkpoint lock again + skip_wal_write_due_to_checkpoint = false; lock.reset(); } @@ -381,37 +433,35 @@ ErrorData DuckTransactionManager::CommitTransaction(ClientContext &context, Tran // We do not need to hold the transaction lock during cleanup of transactions, // as they (1) have been removed, or (2) enter cleanup_info. t_lock.unlock(); - held_wal_lock.reset(); - - { - lock_guard c_lock(cleanup_lock); - unique_ptr top_cleanup_info; - { - lock_guard q_lock(cleanup_queue_lock); - if (!cleanup_queue.empty()) { - top_cleanup_info = std::move(cleanup_queue.front()); - cleanup_queue.pop(); - } - } - if (top_cleanup_info) { - top_cleanup_info->Cleanup(); - } + // if we have skipped the WAL write due to checkpoint, we keep the WAL lock while checkpointing + // this prevents any concurrent transactions from happening during this time + if (!skip_wal_write_due_to_checkpoint) { + held_wal_lock.reset(); } + CleanupTransactions(); + // now perform a checkpoint if (1) we are able to checkpoint, and (2) the WAL has reached sufficient size to // checkpoint if (checkpoint_decision.can_checkpoint) { - D_ASSERT(lock); + if (!lock || lock->GetType() != StorageLockType::EXCLUSIVE) { + throw InternalException("Checkpointing requires an exclusive lock to be held"); + } // we can unlock the transaction lock while checkpointing // checkpoint the database to disk CheckpointOptions options; options.action = CheckpointAction::ALWAYS_CHECKPOINT; options.type = checkpoint_decision.type; + options.wal_lock = held_wal_lock.get(); auto &storage_manager = db.GetStorageManager(); try { storage_manager.CreateCheckpoint(context, options); } catch (std::exception &ex) { - error.Merge(ErrorData(ex)); + // a checkpoint failure here should not result in the commit being turned into a rollback + // .. UNLESS we have skipped writing to the WAL and there are concurrent transactions active + if (skip_wal_write_due_to_checkpoint) { + error.Merge(ErrorData(ex)); + } } } @@ -437,20 +487,7 @@ void DuckTransactionManager::RollbackTransaction(Transaction &transaction_p) { } } - { - lock_guard c_lock(cleanup_lock); - unique_ptr top_cleanup_info; - { - lock_guard q_lock(cleanup_queue_lock); - if (!cleanup_queue.empty()) { - top_cleanup_info = std::move(cleanup_queue.front()); - cleanup_queue.pop(); - } - } - if (top_cleanup_info) { - top_cleanup_info->Cleanup(); - } - } + CleanupTransactions(); if (error.HasError()) { throw FatalException("Failed to rollback transaction. Cannot continue operation.\nError: %s", error.Message()); diff --git a/src/duckdb/src/transaction/transaction_context.cpp b/src/duckdb/src/transaction/transaction_context.cpp index a88f831b0..9c5c3c01e 100644 --- a/src/duckdb/src/transaction/transaction_context.cpp +++ b/src/duckdb/src/transaction/transaction_context.cpp @@ -55,6 +55,10 @@ void TransactionContext::Commit() { for (auto const &s : context.registered_state->States()) { s->TransactionRollback(*transaction, context, error); } + if (Exception::InvalidatesDatabase(error.Type()) || error.Type() == ExceptionType::INTERNAL) { + // throw fatal / internal exceptions directly + error.Throw(); + } throw TransactionException("Failed to commit: %s", error.RawMessage()); } for (auto &state : context.registered_state->States()) { diff --git a/src/duckdb/src/transaction/wal_write_state.cpp b/src/duckdb/src/transaction/wal_write_state.cpp index c0671eec0..bc5160f43 100644 --- a/src/duckdb/src/transaction/wal_write_state.cpp +++ b/src/duckdb/src/transaction/wal_write_state.cpp @@ -158,6 +158,7 @@ void WALWriteState::WriteCatalogEntry(CatalogEntry &entry, data_ptr_t dataptr) { case CatalogType::COPY_FUNCTION_ENTRY: case CatalogType::PRAGMA_FUNCTION_ENTRY: case CatalogType::COLLATION_ENTRY: + case CatalogType::COORDINATE_SYSTEM_ENTRY: case CatalogType::DEPENDENCY_ENTRY: case CatalogType::SECRET_ENTRY: case CatalogType::SECRET_TYPE_ENTRY: diff --git a/src/duckdb/third_party/httplib/httplib.hpp b/src/duckdb/third_party/httplib/httplib.hpp index 409c47d0b..0fa028598 100644 --- a/src/duckdb/third_party/httplib/httplib.hpp +++ b/src/duckdb/third_party/httplib/httplib.hpp @@ -1,27 +1,33 @@ -// taken from: https://github.com/yhirose/cpp-httplib/blob/v0.14.3/httplib.h +// taken from: https://github.com/yhirose/cpp-httplib/blob/v0.27.0/httplib.h // Note: some modifications are made to file (replace std::regex with RE2) +// Patched CreateFile2 for lower Windows versions // // httplib.h // -// Copyright (c) 2023 Yuji Hirose. All rights reserved. +// Copyright (c) 2025 Yuji Hirose. All rights reserved. // MIT License // #ifndef CPPHTTPLIB_HTTPLIB_H #define CPPHTTPLIB_HTTPLIB_H -#define CPPHTTPLIB_VERSION "0.14.3" +#define CPPHTTPLIB_VERSION "0.27.0" +#define CPPHTTPLIB_VERSION_NUM "0x001B00" #include "duckdb/original/std/memory.hpp" #include "duckdb/common/string.hpp" #include #include +/* + * Platform compatibility check + */ /* * Configuration */ + #ifdef CPPHTTPLIB_OPENSSL_SUPPORT #define CPPHTTPLIB_NAMESPACE duckdb_httplib_openssl #else @@ -32,8 +38,12 @@ #define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5 #endif +#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND +#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND 10000 +#endif + #ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT -#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5 +#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 100 #endif #ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND @@ -44,20 +54,40 @@ #define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0 #endif -#ifndef CPPHTTPLIB_READ_TIMEOUT_SECOND -#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5 +#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND +#define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND 5 +#endif + +#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND +#define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND 0 +#endif + +#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND +#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND 5 +#endif + +#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND +#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND 0 +#endif + +#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND +#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND 300 +#endif + +#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND +#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND 0 #endif -#ifndef CPPHTTPLIB_READ_TIMEOUT_USECOND -#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0 +#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND +#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND 5 #endif -#ifndef CPPHTTPLIB_WRITE_TIMEOUT_SECOND -#define CPPHTTPLIB_WRITE_TIMEOUT_SECOND 5 +#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND +#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND 0 #endif -#ifndef CPPHTTPLIB_WRITE_TIMEOUT_USECOND -#define CPPHTTPLIB_WRITE_TIMEOUT_USECOND 0 +#ifndef CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND +#define CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND 0 #endif #ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND @@ -66,7 +96,7 @@ #ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND #ifdef _WIN32 -#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 10000 +#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 1000 #else #define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0 #endif @@ -76,14 +106,14 @@ #define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192 #endif -#ifndef CPPHTTPLIB_USE_POLL -#define CPPHTTPLIB_USE_POLL -#endif - #ifndef CPPHTTPLIB_HEADER_MAX_LENGTH #define CPPHTTPLIB_HEADER_MAX_LENGTH 8192 #endif +#ifndef CPPHTTPLIB_HEADER_MAX_COUNT +#define CPPHTTPLIB_HEADER_MAX_COUNT 100 +#endif + #ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT #define CPPHTTPLIB_REDIRECT_MAX_COUNT 20 #endif @@ -100,12 +130,24 @@ #define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192 #endif +#ifndef CPPHTTPLIB_RANGE_MAX_COUNT +#define CPPHTTPLIB_RANGE_MAX_COUNT 1024 +#endif + #ifndef CPPHTTPLIB_TCP_NODELAY #define CPPHTTPLIB_TCP_NODELAY false #endif +#ifndef CPPHTTPLIB_IPV6_V6ONLY +#define CPPHTTPLIB_IPV6_V6ONLY false +#endif + #ifndef CPPHTTPLIB_RECV_BUFSIZ -#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u) +#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u) +#endif + +#ifndef CPPHTTPLIB_SEND_BUFSIZ +#define CPPHTTPLIB_SEND_BUFSIZ size_t(16384u) #endif #ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ @@ -133,6 +175,34 @@ #define CPPHTTPLIB_LISTEN_BACKLOG 5 #endif +#ifndef CPPHTTPLIB_MAX_LINE_LENGTH +#define CPPHTTPLIB_MAX_LINE_LENGTH 32768 +#endif + +#if defined(__GNUC__) || defined(__clang__) + #define HTTPLIB_DEPRECATED(msg) __attribute__((deprecated(msg))) +#elif defined(_MSC_VER) + #define HTTPLIB_DEPRECATED(msg) __declspec(deprecated(msg)) +#else + #define HTTPLIB_DEPRECATED(msg) +#endif + +#if defined(_WIN32) && !defined(_WIN64) +#if defined(_MSC_VER) +#pragma message( \ + "cpp-httplib doesn't support 32-bit Windows. Please use a 64-bit compiler.") +#else +#warning \ + "cpp-httplib doesn't support 32-bit Windows. Please use a 64-bit compiler." +#endif +#elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ < 8 +#warning \ + "cpp-httplib doesn't support 32-bit platforms. Please use a 64-bit compiler." +#elif defined(__SIZEOF_SIZE_T__) && __SIZEOF_SIZE_T__ < 8 +#warning \ + "cpp-httplib doesn't support platforms where size_t is less than 64 bits." +#endif + /* * Headers */ @@ -153,11 +223,7 @@ #pragma comment(lib, "ws2_32.lib") -#ifdef _WIN64 using ssize_t = __int64; -#else -using ssize_t = long; -#endif #endif // _MSC_VER #ifndef S_ISREG @@ -176,18 +242,21 @@ using ssize_t = long; #include #include +#if defined(__has_include) +#if __has_include() +// afunix.h uses types declared in winsock2.h, so has to be included after it. +#include +#define CPPHTTPLIB_HAVE_AFUNIX_H 1 +#endif +#endif + #ifndef WSA_FLAG_NO_HANDLE_INHERIT #define WSA_FLAG_NO_HANDLE_INHERIT 0x80 #endif -#ifndef strcasecmp -#define strcasecmp _stricmp -#endif // strcasecmp - +using nfds_t = unsigned long; using socket_t = SOCKET; -#ifdef CPPHTTPLIB_USE_POLL -#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout) -#endif +using socklen_t = int; #else // not _WIN32 @@ -207,14 +276,11 @@ using socket_t = SOCKET; #ifdef __linux__ #include #endif +#include #include -#ifdef CPPHTTPLIB_USE_POLL #include -#endif -#include #include #include -#include #include #include #include @@ -225,6 +291,10 @@ using socket_t = int; #endif #endif //_WIN32 +#if defined(__APPLE__) +#include +#endif + #include #include #include @@ -234,8 +304,8 @@ using socket_t = int; #include #include #include +#include #include -#include #include #include #include @@ -254,6 +324,15 @@ using socket_t = int; #include "duckdb/common/re2_regex.hpp" #include "duckdb/common/random_engine.hpp" +#if defined(CPPHTTPLIB_USE_NON_BLOCKING_GETADDRINFO) || \ + defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) +#if TARGET_OS_MAC +#include +#include +#endif +#endif // CPPHTTPLIB_USE_NON_BLOCKING_GETADDRINFO or + // CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN + #ifdef CPPHTTPLIB_OPENSSL_SUPPORT #ifdef _WIN32 #include @@ -268,14 +347,14 @@ using socket_t = int; #ifdef _MSC_VER #pragma comment(lib, "crypt32.lib") #endif -#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__) -#include -#if TARGET_OS_OSX -#include -#include -#endif // TARGET_OS_OSX #endif // _WIN32 +#if defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) +#if TARGET_OS_MAC +#include +#endif +#endif // CPPHTTPLIB_USE_NON_BLOCKING_GETADDRINFO + #include #include #include @@ -289,15 +368,20 @@ using socket_t = int; #include #include - +#if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x1010107f +#error Please use OpenSSL or a current version of BoringSSL +#endif +#define SSL_get1_peer_certificate SSL_get_peer_certificate // Disabled OpenSSL version check for CI -//#if OPENSSL_VERSION_NUMBER < 0x1010100fL -//#error Sorry, OpenSSL versions prior to 1.1.1 are not supported -#if OPENSSL_VERSION_NUMBER < 0x30000000L +//#elif OPENSSL_VERSION_NUMBER < 0x30000000L +//#error Sorry, OpenSSL versions prior to 3.0.0 are not supported +//#endif +#elif OPENSSL_VERSION_NUMBER < 0x30000000L #define SSL_get1_peer_certificate SSL_get_peer_certificate #endif -#endif +#endif // CPPHTTPLIB_OPENSSL_SUPPORT #ifdef CPPHTTPLIB_ZLIB_SUPPORT #include @@ -308,9 +392,14 @@ using socket_t = int; #include #endif +#ifdef CPPHTTPLIB_ZSTD_SUPPORT +#include +#endif + /* * Declaration */ + namespace CPPHTTPLIB_NAMESPACE { namespace detail { @@ -336,16 +425,67 @@ make_unique(std::size_t n) { return duckdb::unique_ptr(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 case_ignore { + +inline unsigned char to_lower(int c) { + const static unsigned char table[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, 215, 248, 249, 250, 251, 252, 253, 254, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, + }; + return table[(unsigned char)(char)c]; +} + +inline bool equal(const std::string &a, const std::string &b) { + return a.size() == b.size() && + std::equal(a.begin(), a.end(), b.begin(), [](char ca, char cb) { + return to_lower(ca) == to_lower(cb); + }); +} + +struct equal_to { + bool operator()(const std::string &a, const std::string &b) const { + return equal(a, b); } }; +struct hash { + size_t operator()(const std::string &key) const { + return hash_core(key.data(), key.size(), 0); + } + + size_t hash_core(const char *s, size_t l, size_t h) const { + return (l == 0) ? h + : hash_core(s + 1, l - 1, + // Unsets the 6 high bits of h, therefore no + // overflow happens + (((std::numeric_limits::max)() >> 6) & + h * 33) ^ + static_cast(to_lower(*s))); + } +}; + +template +using unordered_set = std::unordered_set; + +} // namespace case_ignore + // This is based on // "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189". @@ -376,6 +516,15 @@ struct scope_exit { } // namespace detail +enum SSLVerifierResponse { + // no decision has been made, use the built-in certificate verifier + NoDecisionMade, + // connection certificate is verified and accepted + CertificateAccepted, + // connection certificate was processed but is rejected + CertificateRejected +}; + enum StatusCode { // Information responses Continue_100 = 100, @@ -451,25 +600,61 @@ enum StatusCode { NetworkAuthenticationRequired_511 = 511, }; -using Headers = std::multimap; +using Headers = + std::unordered_multimap; using Params = std::multimap; using Match = duckdb_re2::Match; using Regex = duckdb_re2::Regex; -using Progress = std::function; +using DownloadProgress = std::function; +using UploadProgress = std::function; struct Response; using ResponseHandler = std::function; +struct FormData { + std::string name; + std::string content; + std::string filename; + std::string content_type; + Headers headers; +}; + +struct FormField { + std::string name; + std::string content; + Headers headers; +}; +using FormFields = std::multimap; + +using FormFiles = std::multimap; + struct MultipartFormData { + FormFields fields; // Text fields from multipart + FormFiles files; // Files from multipart + + // Text field access + std::string get_field(const std::string &key, size_t id = 0) const; + std::vector get_fields(const std::string &key) const; + bool has_field(const std::string &key) const; + size_t get_field_count(const std::string &key) const; + + // File access + FormData get_file(const std::string &key, size_t id = 0) const; + std::vector get_files(const std::string &key) const; + bool has_file(const std::string &key) const; + size_t get_file_count(const std::string &key) const; +}; + +struct UploadFormData { std::string name; std::string content; std::string filename; std::string content_type; }; -using MultipartFormDataItems = std::vector; -using MultipartFormDataMap = std::multimap; +using UploadFormDataItems = std::vector; class DataSink { public: @@ -487,7 +672,7 @@ class DataSink { std::ostream os; private: - class data_sink_streambuf : public std::streambuf { + class data_sink_streambuf final : public std::streambuf { public: explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {} @@ -512,37 +697,34 @@ using ContentProviderWithoutLength = using ContentProviderResourceReleaser = std::function; -struct MultipartFormDataProvider { +struct FormDataProvider { std::string name; ContentProviderWithoutLength provider; std::string filename; std::string content_type; }; -using MultipartFormDataProviderItems = std::vector; +using FormDataProviderItems = std::vector; -using ContentReceiverWithProgress = - std::function; +using ContentReceiverWithProgress = std::function; using ContentReceiver = std::function; -using MultipartContentHeader = - std::function; +using FormDataHeader = std::function; class ContentReader { public: using Reader = std::function; - using MultipartReader = std::function; + using FormDataReader = + std::function; - ContentReader(Reader reader, MultipartReader multipart_reader) + ContentReader(Reader reader, FormDataReader multipart_reader) : reader_(std::move(reader)), - multipart_reader_(std::move(multipart_reader)) {} + formdata_reader_(std::move(multipart_reader)) {} - bool operator()(MultipartContentHeader header, - ContentReceiver receiver) const { - return multipart_reader_(std::move(header), std::move(receiver)); + bool operator()(FormDataHeader header, ContentReceiver receiver) const { + return formdata_reader_(std::move(header), std::move(receiver)); } bool operator()(ContentReceiver receiver) const { @@ -550,7 +732,7 @@ class ContentReader { } Reader reader_; - MultipartReader multipart_reader_; + FormDataReader formdata_reader_; }; using Range = std::pair; @@ -559,7 +741,10 @@ using Ranges = std::vector; struct Request { std::string method; std::string path; + std::string matched_route; + Params params; Headers headers; + Headers trailers; std::string body; std::string remote_addr; @@ -570,42 +755,48 @@ struct Request { // for server std::string version; std::string target; - Params params; - MultipartFormDataMap files; + MultipartFormData form; Ranges ranges; Match matches; std::unordered_map path_params; + std::function is_connection_closed = []() { return true; }; // for client + std::vector accept_content_types; ResponseHandler response_handler; ContentReceiverWithProgress content_receiver; - Progress progress; + DownloadProgress download_progress; + UploadProgress upload_progress; #ifdef CPPHTTPLIB_OPENSSL_SUPPORT const SSL *ssl = nullptr; #endif bool has_header(const std::string &key) const; - std::string get_header_value(const std::string &key, size_t id = 0) const; - uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const; + std::string get_header_value(const std::string &key, const char *def = "", + size_t id = 0) const; + size_t get_header_value_u64(const std::string &key, size_t def = 0, + size_t id = 0) const; size_t get_header_value_count(const std::string &key) const; void set_header(const std::string &key, const std::string &val); + bool has_trailer(const std::string &key) const; + std::string get_trailer_value(const std::string &key, size_t id = 0) const; + size_t get_trailer_value_count(const std::string &key) const; + bool has_param(const std::string &key) const; std::string get_param_value(const std::string &key, size_t id = 0) const; size_t get_param_value_count(const std::string &key) const; bool is_multipart_form_data() const; - bool has_file(const std::string &key) const; - MultipartFormData get_file_value(const std::string &key) const; - std::vector get_file_values(const std::string &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; + std::chrono::time_point start_time_ = + (std::chrono::steady_clock::time_point::min)(); }; struct Response { @@ -613,18 +804,26 @@ struct Response { int status = -1; std::string reason; Headers headers; + Headers trailers; std::string body; std::string location; // Redirect location bool has_header(const std::string &key) const; - std::string get_header_value(const std::string &key, size_t id = 0) const; - uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const; + std::string get_header_value(const std::string &key, const char *def = "", + size_t id = 0) const; + size_t get_header_value_u64(const std::string &key, size_t def = 0, + size_t id = 0) const; size_t get_header_value_count(const std::string &key) const; void set_header(const std::string &key, const std::string &val); + bool has_trailer(const std::string &key) const; + std::string get_trailer_value(const std::string &key, size_t id = 0) const; + size_t get_trailer_value_count(const std::string &key) const; + void set_redirect(const std::string &url, int status = StatusCode::Found_302); void set_content(const char *s, size_t n, const std::string &content_type); void set_content(const std::string &s, const std::string &content_type); + void set_content(std::string &&s, const std::string &content_type); void set_content_provider( size_t length, const std::string &content_type, ContentProvider provider, @@ -638,6 +837,10 @@ struct Response { const std::string &content_type, ContentProviderWithoutLength provider, ContentProviderResourceReleaser resource_releaser = nullptr); + void set_file_content(const std::string &path, + const std::string &content_type); + void set_file_content(const std::string &path); + Response() = default; Response(const Response &) = default; Response &operator=(const Response &) = default; @@ -655,6 +858,8 @@ struct Response { ContentProviderResourceReleaser content_provider_resource_releaser_; bool is_chunked_content_provider_ = false; bool content_provider_success_ = false; + std::string file_content_path_; + std::string file_content_content_type_; }; class Stream { @@ -662,7 +867,8 @@ class Stream { virtual ~Stream() = default; virtual bool is_readable() const = 0; - virtual bool is_writable() const = 0; + virtual bool wait_readable() const = 0; + virtual bool wait_writable() const = 0; virtual ssize_t read(char *ptr, size_t size) = 0; virtual ssize_t write(const char *ptr, size_t size) = 0; @@ -670,8 +876,8 @@ class Stream { virtual void get_local_ip_and_port(std::string &ip, int &port) const = 0; virtual socket_t socket() const = 0; - template - ssize_t write_format(const char *fmt, const Args &...args); + virtual time_t duration() const = 0; + ssize_t write(const char *ptr); ssize_t write(const std::string &s); }; @@ -681,15 +887,16 @@ class TaskQueue { TaskQueue() = default; virtual ~TaskQueue() = default; - virtual void enqueue(std::function fn) = 0; + virtual bool enqueue(std::function fn) = 0; virtual void shutdown() = 0; virtual void on_idle() {} }; -class ThreadPool : public TaskQueue { +class ThreadPool final : public TaskQueue { public: - explicit ThreadPool(size_t n) : shutdown_(false) { + explicit ThreadPool(size_t n, size_t mqr = 0) + : shutdown_(false), max_queued_requests_(mqr) { while (n) { threads_.emplace_back(worker(*this)); n--; @@ -699,19 +906,23 @@ class ThreadPool : public TaskQueue { ThreadPool(const ThreadPool &) = delete; ~ThreadPool() override = default; - void enqueue(std::function fn) override { + bool enqueue(std::function fn) override { { - std::unique_lock lock(mutex_); + duckdb::unique_lock lock(mutex_); + if (max_queued_requests_ > 0 && jobs_.size() >= max_queued_requests_) { + return false; + } jobs_.push_back(std::move(fn)); } cond_.notify_one(); + return true; } void shutdown() override { // Stop all worker threads... { - std::unique_lock lock(mutex_); + duckdb::unique_lock lock(mutex_); shutdown_ = true; } @@ -731,20 +942,25 @@ class ThreadPool : public TaskQueue { for (;;) { std::function fn; { - std::unique_lock lock(pool_.mutex_); + duckdb::unique_lock lock(pool_.mutex_); pool_.cond_.wait( lock, [&] { return !pool_.jobs_.empty() || pool_.shutdown_; }); if (pool_.shutdown_ && pool_.jobs_.empty()) { break; } - fn = std::move(pool_.jobs_.front()); + fn = pool_.jobs_.front(); pool_.jobs_.pop_front(); } assert(true == static_cast(fn)); fn(); } + +#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && !defined(OPENSSL_IS_BORINGSSL) && \ + !defined(LIBRESSL_VERSION_NUMBER) + OPENSSL_thread_stop(); +#endif } ThreadPool &pool_; @@ -755,6 +971,7 @@ class ThreadPool : public TaskQueue { std::list> jobs_; bool shutdown_; + size_t max_queued_requests_ = 0; std::condition_variable cond_; std::mutex mutex_; @@ -762,27 +979,49 @@ class ThreadPool : public TaskQueue { using Logger = std::function; +// Forward declaration for Error type +enum class Error; +using ErrorLogger = std::function; + using SocketOptions = std::function; +namespace detail { + +bool set_socket_opt_impl(socket_t sock, int level, int optname, + const void *optval, socklen_t optlen); +bool set_socket_opt(socket_t sock, int level, int optname, int opt); +bool set_socket_opt_time(socket_t sock, int level, int optname, time_t sec, + time_t usec); + +} // namespace detail + void default_socket_options(socket_t sock); const char *status_message(int status); +std::string get_bearer_token_auth(const Request &req); + namespace detail { class MatcherBase { public: + MatcherBase(std::string pattern) : pattern_(pattern) {} virtual ~MatcherBase() = default; + const std::string &pattern() const { return pattern_; } + // Match request path and populate its matches and virtual bool match(Request &request) const = 0; + +private: + std::string pattern_; }; /** * Captures parameters in request path and stores them in Request::path_params * * Capture name is a substring of a pattern from : to /. - * The rest of the pattern is matched agains the request path directly + * The rest of the pattern is matched against the request path directly * Parameters are captured starting from the next character after * the end of the last matched static pattern fragment until the next /. * @@ -796,14 +1035,13 @@ class MatcherBase { * the resulting capture will be * {{"capture", "1"}, {"second_capture", "2"}} */ -class PathParamsMatcher : public MatcherBase { +class PathParamsMatcher final : public MatcherBase { public: PathParamsMatcher(const std::string &pattern); bool match(Request &request) const override; private: - static constexpr char marker = ':'; // Treat segment separators as the end of path parameter capture // Does not need to handle query parameters as they are parsed before path // matching @@ -826,9 +1064,10 @@ class PathParamsMatcher : public MatcherBase { * This means that wildcard patterns may match multiple path segments with /: * "/begin/(.*)/end" will match both "/begin/middle/end" and "/begin/1/2/end". */ -class RegexMatcher : public MatcherBase { +class RegexMatcher final : public MatcherBase { public: - RegexMatcher(const std::string &pattern) : regex_(pattern) {} + RegexMatcher(const std::string &pattern) + : MatcherBase(pattern), regex_(pattern) {} bool match(Request &request) const override; @@ -838,6 +1077,9 @@ class RegexMatcher : public MatcherBase { ssize_t write_headers(Stream &strm, const Headers &headers); +std::string make_host_and_port_string(const std::string &host, int port, + bool is_ssl); + } // namespace detail class Server { @@ -887,23 +1129,36 @@ class Server { Server &set_default_file_mimetype(const std::string &mime); Server &set_file_request_handler(Handler handler); - Server &set_error_handler(HandlerWithResponse handler); - Server &set_error_handler(Handler handler); + template + Server &set_error_handler(ErrorHandlerFunc &&handler) { + return set_error_handler_core( + std::forward(handler), + std::is_convertible{}); + } + Server &set_exception_handler(ExceptionHandler handler); + Server &set_pre_routing_handler(HandlerWithResponse handler); Server &set_post_routing_handler(Handler handler); + Server &set_pre_request_handler(HandlerWithResponse handler); + Server &set_expect_100_continue_handler(Expect100ContinueHandler handler); Server &set_logger(Logger logger); + Server &set_pre_compression_logger(Logger logger); + Server &set_error_logger(ErrorLogger error_logger); Server &set_address_family(int family); Server &set_tcp_nodelay(bool on); + Server &set_ipv6_v6only(bool on); Server &set_socket_options(SocketOptions socket_options); Server &set_default_headers(Headers headers); Server & set_header_writer(std::function const &writer); + Server &set_trusted_proxies(const std::vector &proxies); + Server &set_keep_alive_max_count(size_t count); Server &set_keep_alive_timeout(time_t sec); @@ -930,33 +1185,41 @@ class Server { bool is_running() const; void wait_until_ready() const; void stop(); + void decommission(); std::function new_task_queue; protected: - bool process_request(Stream &strm, bool close_connection, + bool process_request(Stream &strm, const std::string &remote_addr, + int remote_port, const std::string &local_addr, + int local_port, bool close_connection, bool &connection_closed, const std::function &setup_request); std::atomic svr_sock_{INVALID_SOCKET}; + + std::vector trusted_proxies_; + 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 read_timeout_sec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND; + time_t read_timeout_usec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND; + time_t write_timeout_sec_ = CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND; + time_t write_timeout_usec_ = CPPHTTPLIB_SERVER_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>; - using HandlersForContentReader = - std::vector>; + using Handlers = std::vector>; + using HandlersForContentReader = std::vector>; - static duckdb::unique_ptr + static duckdb::unique_ptr make_matcher(const std::string &pattern); + Server &set_error_handler_core(HandlerWithResponse handler, std::true_type); + Server &set_error_handler_core(Handler handler, std::false_type); + socket_t create_server_socket(const std::string &host, int port, int socket_flags, SocketOptions socket_options) const; @@ -964,8 +1227,7 @@ class Server { bool listen_internal(); bool routing(Request &req, Response &res, Stream &strm); - bool handle_file_request(const Request &req, Response &res, - bool head = false); + bool handle_file_request(const Request &req, Response &res); bool dispatch_request(Request &req, Response &res, const Handlers &handlers) const; bool dispatch_request_for_content_reader( @@ -975,7 +1237,7 @@ class Server { bool parse_request_line(const char *s, Request &req) const; void apply_ranges(const Request &req, Response &res, std::string &content_type, std::string &boundary) const; - bool write_response(Stream &strm, bool close_connection, const Request &req, + bool write_response(Stream &strm, bool close_connection, Request &req, Response &res); bool write_response_with_content(Stream &strm, bool close_connection, const Request &req, Response &res); @@ -986,20 +1248,25 @@ class Server { 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_with_content_receiver(Stream &strm, Request &req, + Response &res, + ContentReceiver receiver, + FormDataHeader multipart_header, + ContentReceiver multipart_receiver); bool read_content_core(Stream &strm, Request &req, Response &res, ContentReceiver receiver, - MultipartContentHeader multipart_header, + FormDataHeader multipart_header, ContentReceiver multipart_receiver) const; virtual bool process_and_close_socket(socket_t sock); + void output_log(const Request &req, const Response &res) const; + void output_pre_compression_log(const Request &req, + const Response &res) const; + void output_error_log(const Error &err, const Request *req) const; + std::atomic is_running_{false}; - std::atomic done_{false}; + std::atomic is_decommissioned{false}; struct MountPointEntry { std::string mount_point; @@ -1026,12 +1293,17 @@ class Server { ExceptionHandler exception_handler_; HandlerWithResponse pre_routing_handler_; Handler post_routing_handler_; + HandlerWithResponse pre_request_handler_; Expect100ContinueHandler expect_100_continue_handler_; + mutable std::mutex logger_mutex_; Logger logger_; + Logger pre_compression_logger_; + ErrorLogger error_logger_; int address_family_ = AF_UNSPEC; bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY; + bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY; SocketOptions socket_options_ = default_socket_options; Headers default_headers_; @@ -1051,10 +1323,27 @@ enum class Error { SSLConnection, SSLLoadingCerts, SSLServerVerification, + SSLServerHostnameVerification, UnsupportedMultipartBoundaryChars, Compression, ConnectionTimeout, ProxyConnection, + ResourceExhaustion, + TooManyFormDataFiles, + ExceedMaxPayloadSize, + ExceedUriMaxLength, + ExceedMaxSocketDescriptorCount, + InvalidRequestLine, + InvalidHTTPMethod, + InvalidHTTPVersion, + InvalidHeaders, + MultipartParsing, + OpenFile, + Listen, + GetSockName, + UnsupportedAddressFamily, + HTTPParsing, + InvalidRangeHeader, // For internal use only SSLPeerCouldBeClosed_, @@ -1071,6 +1360,17 @@ class Result { Headers &&request_headers = Headers{}) : res_(std::move(res)), err_(err), request_headers_(std::move(request_headers)) {} +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + Result(duckdb::unique_ptr &&res, Error err, Headers &&request_headers, + int ssl_error) + : res_(std::move(res)), err_(err), + request_headers_(std::move(request_headers)), ssl_error_(ssl_error) {} + Result(duckdb::unique_ptr &&res, Error err, Headers &&request_headers, + int ssl_error, unsigned long ssl_openssl_error) + : res_(std::move(res)), err_(err), + request_headers_(std::move(request_headers)), ssl_error_(ssl_error), + ssl_openssl_error_(ssl_openssl_error) {} +#endif // Response operator bool() const { return res_ != nullptr; } bool operator==(std::nullptr_t) const { return res_ == nullptr; } @@ -1085,18 +1385,30 @@ class Result { // Error Error error() const { return err_; } +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + // SSL Error + int ssl_error() const { return ssl_error_; } + // OpenSSL Error + unsigned long ssl_openssl_error() const { return ssl_openssl_error_; } +#endif + // Request Headers bool has_request_header(const std::string &key) const; std::string get_request_header_value(const std::string &key, + const char *def = "", size_t id = 0) const; - uint64_t get_request_header_value_u64(const std::string &key, - size_t id = 0) const; + size_t get_request_header_value_u64(const std::string &key, size_t def = 0, + size_t id = 0) const; size_t get_request_header_value_count(const std::string &key) const; private: duckdb::unique_ptr res_; Error err_ = Error::Unknown; Headers request_headers_; +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + int ssl_error_ = 0; + unsigned long ssl_openssl_error_ = 0; +#endif }; class ClientImpl { @@ -1113,144 +1425,86 @@ class ClientImpl { virtual bool is_valid() const; - Result Get(const std::string &path); - Result Get(const std::string &path, const Headers &headers); - Result Get(const std::string &path, Progress progress); - Result Get(const std::string &path, const Headers &headers, - Progress progress); - Result Get(const std::string &path, ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver); - Result Get(const std::string &path, ContentReceiver content_receiver, - Progress progress); - Result Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver, Progress progress); - Result Get(const std::string &path, ResponseHandler response_handler, - ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver); - Result Get(const std::string &path, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress); - Result Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, ContentReceiver content_receiver, - Progress progress); - - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, Progress progress = nullptr); - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, ContentReceiver content_receiver, - Progress progress = nullptr); - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress = nullptr); + // clang-format off + Result Get(const std::string &path, DownloadProgress progress = nullptr); + Result Get(const std::string &path, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Headers &headers, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Headers &headers, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, const Headers &headers, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, const Headers &headers, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr); Result Head(const std::string &path); Result Head(const std::string &path, const Headers &headers); Result Post(const std::string &path); - Result Post(const std::string &path, const Headers &headers); - Result Post(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, const char *body, - size_t content_length, const std::string &content_type); - Result Post(const std::string &path, const std::string &body, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Post(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type); - Result Post(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); + Result Post(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); Result Post(const std::string &path, const Params ¶ms); - Result Post(const std::string &path, const Headers &headers, - const Params ¶ms); - Result Post(const std::string &path, const MultipartFormDataItems &items); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, const std::string &boundary); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items); + Result Post(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers); + Result Post(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const Params ¶ms); + Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr); Result Put(const std::string &path); - Result Put(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, const char *body, - size_t content_length, const std::string &content_type); - Result Put(const std::string &path, const std::string &body, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Put(const std::string &path, size_t content_length, - ContentProvider content_provider, const std::string &content_type); - Result Put(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); + Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); Result Put(const std::string &path, const Params ¶ms); - Result Put(const std::string &path, const Headers &headers, - const Params ¶ms); - Result Put(const std::string &path, const MultipartFormDataItems &items); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, const std::string &boundary); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items); + Result Put(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers); + Result Put(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const Params ¶ms); + Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr); Result Patch(const std::string &path); - Result Patch(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type); - Result Patch(const std::string &path, const std::string &body, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Patch(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type); - Result Patch(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - - Result Delete(const std::string &path); - Result Delete(const std::string &path, const Headers &headers); - Result Delete(const std::string &path, const char *body, - size_t content_length, const std::string &content_type); - Result Delete(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type); - Result Delete(const std::string &path, const std::string &body, - const std::string &content_type); - Result Delete(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); + Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Params ¶ms); + Result Patch(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const Params ¶ms); + Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + + Result Delete(const std::string &path, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const std::string &body, const std::string &content_type, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Params ¶ms, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Headers &headers, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Headers &headers, const Params ¶ms, DownloadProgress progress = nullptr); Result Options(const std::string &path); Result Options(const std::string &path, const Headers &headers); + // clang-format on bool send(Request &req, Response &res, Error &error); Result send(const Request &req); @@ -1272,6 +1526,7 @@ class ClientImpl { void set_address_family(int family); void set_tcp_nodelay(bool on); + void set_ipv6_v6only(bool on); void set_socket_options(SocketOptions socket_options); void set_connection_timeout(time_t sec, time_t usec = 0); @@ -1287,6 +1542,10 @@ class ClientImpl { template void set_write_timeout(const std::chrono::duration &duration); + void set_max_timeout(time_t msec); + template + void set_max_timeout(const std::chrono::duration &duration); + void set_basic_auth(const std::string &username, const std::string &password); void set_bearer_token_auth(const std::string &token); #ifdef CPPHTTPLIB_OPENSSL_SUPPORT @@ -1297,7 +1556,7 @@ class ClientImpl { void set_keep_alive(bool on); void set_follow_location(bool on); - void set_url_encode(bool on); + void set_path_encode(bool on); void set_compress(bool on); @@ -1323,9 +1582,13 @@ class ClientImpl { #ifdef CPPHTTPLIB_OPENSSL_SUPPORT void enable_server_certificate_verification(bool enabled); + void enable_server_hostname_verification(bool enabled); + void set_server_certificate_verifier( + std::function verifier); #endif void set_logger(Logger logger); + void set_error_logger(ErrorLogger error_logger); protected: struct Socket { @@ -1358,6 +1621,9 @@ class ClientImpl { void copy_settings(const ClientImpl &rhs); + void output_log(const Request &req, const Response &res) const; + void output_error_log(const Error &err, const Request *req) const; + // Socket endpoint information const std::string host_; const int port_; @@ -1389,10 +1655,11 @@ class ClientImpl { 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; + time_t read_timeout_sec_ = CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND; + time_t read_timeout_usec_ = CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND; + time_t write_timeout_sec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND; + time_t write_timeout_usec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND; + time_t max_timeout_msec_ = CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND; std::string basic_auth_username_; std::string basic_auth_password_; @@ -1405,10 +1672,11 @@ class ClientImpl { bool keep_alive_ = false; bool follow_location_ = false; - bool url_encode_ = true; + bool path_encode_ = true; int address_family_ = AF_UNSPEC; bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY; + bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY; SocketOptions socket_options_ = nullptr; bool compress_ = false; @@ -1436,9 +1704,18 @@ class ClientImpl { #ifdef CPPHTTPLIB_OPENSSL_SUPPORT bool server_certificate_verification_ = true; + bool server_hostname_verification_ = true; + std::function server_certificate_verifier_; #endif + mutable std::mutex logger_mutex_; Logger logger_; + ErrorLogger error_logger_; + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + int last_ssl_error_ = 0; + unsigned long last_openssl_error_ = 0; +#endif private: bool send_(Request &req, Response &res, Error &error); @@ -1450,6 +1727,11 @@ class ClientImpl { bool write_request(Stream &strm, Request &req, bool close_connection, Error &error); bool redirect(Request &req, Response &res, Error &error); + bool create_redirect_client(const std::string &scheme, + const std::string &host, int port, Request &req, + Response &res, const std::string &path, + const std::string &location, Error &error); + template void setup_redirect_client(ClientType &client); bool handle_request(Stream &strm, Request &req, Response &res, bool close_connection, Error &error); duckdb::unique_ptr send_with_content_provider( @@ -1462,15 +1744,15 @@ class ClientImpl { const Headers &headers, const char *body, size_t content_length, ContentProvider content_provider, ContentProviderWithoutLength content_provider_without_length, - const std::string &content_type); + const std::string &content_type, UploadProgress progress); ContentProviderWithoutLength get_multipart_content_provider( - const std::string &boundary, const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) const; + const std::string &boundary, const UploadFormDataItems &items, + const FormDataProviderItems &provider_items) const; - std::string adjust_host_string(const std::string &host) const; - - virtual bool process_socket(const Socket &socket, - std::function callback); + virtual bool + process_socket(const Socket &socket, + std::chrono::time_point start_time, + std::function callback); virtual bool is_ssl() const; }; @@ -1491,149 +1773,92 @@ class Client { const std::string &client_key_path); Client(Client &&) = default; + Client &operator=(Client &&) = default; ~Client(); bool is_valid() const; - Result Get(const std::string &path); - Result Get(const std::string &path, const Headers &headers); - Result Get(const std::string &path, Progress progress); - Result Get(const std::string &path, const Headers &headers, - Progress progress); - Result Get(const std::string &path, ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver); - Result Get(const std::string &path, ContentReceiver content_receiver, - Progress progress); - Result Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver, Progress progress); - Result Get(const std::string &path, ResponseHandler response_handler, - ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, ContentReceiver content_receiver, - Progress progress); - Result Get(const std::string &path, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress); - - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, Progress progress = nullptr); - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, ContentReceiver content_receiver, - Progress progress = nullptr); - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress = nullptr); + // clang-format off + Result Get(const std::string &path, DownloadProgress progress = nullptr); + Result Get(const std::string &path, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Headers &headers, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Headers &headers, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, const Headers &headers, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, const Headers &headers, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + Result Get(const std::string &path, const Params ¶ms, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, DownloadProgress progress = nullptr); Result Head(const std::string &path); Result Head(const std::string &path, const Headers &headers); Result Post(const std::string &path); - Result Post(const std::string &path, const Headers &headers); - Result Post(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, const char *body, - size_t content_length, const std::string &content_type); - Result Post(const std::string &path, const std::string &body, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Post(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type); - Result Post(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); + Result Post(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); Result Post(const std::string &path, const Params ¶ms); - Result Post(const std::string &path, const Headers &headers, - const Params ¶ms); - Result Post(const std::string &path, const MultipartFormDataItems &items); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, const std::string &boundary); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items); + Result Post(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers); + Result Post(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const Params ¶ms); + Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr); + Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr); Result Put(const std::string &path); - Result Put(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, const char *body, - size_t content_length, const std::string &content_type); - Result Put(const std::string &path, const std::string &body, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Put(const std::string &path, size_t content_length, - ContentProvider content_provider, const std::string &content_type); - Result Put(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); + Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); Result Put(const std::string &path, const Params ¶ms); - Result Put(const std::string &path, const Headers &headers, - const Params ¶ms); - Result Put(const std::string &path, const MultipartFormDataItems &items); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, const std::string &boundary); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items); + Result Put(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers); + Result Put(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const Params ¶ms); + Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr); + Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr); Result Patch(const std::string &path); - Result Patch(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type); - Result Patch(const std::string &path, const std::string &body, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Patch(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type); - Result Patch(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - - Result Delete(const std::string &path); - Result Delete(const std::string &path, const Headers &headers); - Result Delete(const std::string &path, const char *body, - size_t content_length, const std::string &content_type); - Result Delete(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type); - Result Delete(const std::string &path, const std::string &body, - const std::string &content_type); - Result Delete(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); + Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Params ¶ms); + Result Patch(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers); + Result Patch(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const Params ¶ms); + Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const FormDataProviderItems &provider_items, UploadProgress progress = nullptr); + Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr); + + Result Delete(const std::string &path, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const std::string &body, const std::string &content_type, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Params ¶ms, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Headers &headers, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, DownloadProgress progress = nullptr); + Result Delete(const std::string &path, const Headers &headers, const Params ¶ms, DownloadProgress progress = nullptr); Result Options(const std::string &path); Result Options(const std::string &path, const Headers &headers); + // clang-format on bool send(Request &req, Response &res, Error &error); Result send(const Request &req); @@ -1670,6 +1895,10 @@ class Client { template void set_write_timeout(const std::chrono::duration &duration); + void set_max_timeout(time_t msec); + template + void set_max_timeout(const std::chrono::duration &duration); + void set_basic_auth(const std::string &username, const std::string &password); void set_bearer_token_auth(const std::string &token); #ifdef CPPHTTPLIB_OPENSSL_SUPPORT @@ -1680,6 +1909,7 @@ class Client { void set_keep_alive(bool on); void set_follow_location(bool on); + void set_path_encode(bool on); void set_url_encode(bool on); void set_compress(bool on); @@ -1699,9 +1929,13 @@ class Client { #ifdef CPPHTTPLIB_OPENSSL_SUPPORT void enable_server_certificate_verification(bool enabled); + void enable_server_hostname_verification(bool enabled); + void set_server_certificate_verifier( + std::function verifier); #endif void set_logger(Logger logger); + void set_error_logger(ErrorLogger error_logger); // SSL #ifdef CPPHTTPLIB_OPENSSL_SUPPORT @@ -1744,14 +1978,23 @@ class SSLServer : public Server { SSL_CTX *ssl_context() const; + void update_certs(X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store = nullptr); + + int ssl_last_error() const { return last_ssl_error_; } + private: bool process_and_close_socket(socket_t sock) override; + STACK_OF(X509_NAME) * extract_ca_names_from_x509_store(X509_STORE *store); + SSL_CTX *ctx_; std::mutex ctx_mutex_; + + int last_ssl_error_ = 0; }; -class SSLClient : public ClientImpl { +class SSLClient final : public ClientImpl { public: explicit SSLClient(const std::string &host); @@ -1759,10 +2002,12 @@ class SSLClient : public ClientImpl { explicit SSLClient(const std::string &host, int port, const std::string &client_cert_path, - const std::string &client_key_path); + const std::string &client_key_path, + const std::string &private_key_password = std::string()); explicit SSLClient(const std::string &host, int port, X509 *client_cert, - EVP_PKEY *client_key); + EVP_PKEY *client_key, + const std::string &private_key_password = std::string()); ~SSLClient() override; @@ -1780,12 +2025,16 @@ class SSLClient : public ClientImpl { void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override; void shutdown_ssl_impl(Socket &socket, bool shutdown_gracefully); - bool process_socket(const Socket &socket, - std::function callback) override; + bool + process_socket(const Socket &socket, + std::chrono::time_point start_time, + std::function callback) override; bool is_ssl() const override; - bool connect_with_proxy(Socket &sock, Response &res, bool &success, - Error &error); + bool connect_with_proxy( + Socket &sock, + std::chrono::time_point start_time, + Response &res, bool &success, Error &error); bool initialize_ssl(Socket &socket, Error &error); bool load_certs(); @@ -1822,70 +2071,91 @@ inline void duration_to_sec_and_usec(const T &duration, U callback) { callback(static_cast(sec), static_cast(usec)); } -inline uint64_t get_header_value_u64(const Headers &headers, - const std::string &key, size_t id, - uint64_t def) { +template inline constexpr size_t str_len(const char (&)[N]) { + return N - 1; +} + +inline bool is_numeric(const std::string &str) { + return !str.empty() && + std::all_of(str.cbegin(), str.cend(), + [](unsigned char c) { return std::isdigit(c); }); +} + +inline size_t get_header_value_u64(const Headers &headers, + const std::string &key, size_t def, + size_t id, bool &is_invalid_value) { + is_invalid_value = false; auto rng = headers.equal_range(key); auto it = rng.first; std::advance(it, static_cast(id)); if (it != rng.second) { - return std::strtoull(it->second.data(), nullptr, 10); + if (is_numeric(it->second)) { + return std::strtoull(it->second.data(), nullptr, 10); + } else { + is_invalid_value = true; + } } return def; } +inline size_t get_header_value_u64(const Headers &headers, + const std::string &key, size_t def, + size_t id) { + auto dummy = false; + return get_header_value_u64(headers, key, def, id, dummy); +} + } // namespace detail -inline uint64_t Request::get_header_value_u64(const std::string &key, - size_t id) const { - return detail::get_header_value_u64(headers, key, id, 0); +inline size_t Request::get_header_value_u64(const std::string &key, size_t def, + size_t id) const { + return detail::get_header_value_u64(headers, key, def, id); } -inline uint64_t Response::get_header_value_u64(const std::string &key, - size_t id) const { - return detail::get_header_value_u64(headers, key, id, 0); +inline size_t Response::get_header_value_u64(const std::string &key, size_t def, + size_t id) const { + return detail::get_header_value_u64(headers, key, def, id); } -template -inline ssize_t Stream::write_format(const char *fmt, const Args &...args) { - const auto bufsiz = 2048; - std::array buf{}; - - auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...); - if (sn <= 0) { return sn; } - - auto n = static_cast(sn); +namespace detail { - if (n >= buf.size() - 1) { - std::vector glowable_buf(buf.size()); +inline bool set_socket_opt_impl(socket_t sock, int level, int optname, + const void *optval, socklen_t optlen) { + return setsockopt(sock, level, optname, +#ifdef _WIN32 + reinterpret_cast(optval), +#else + optval, +#endif + optlen) == 0; +} - while (n >= glowable_buf.size() - 1) { - glowable_buf.resize(glowable_buf.size() * 2); - n = static_cast( - snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...)); - } - return write(&glowable_buf[0], n); - } else { - return write(buf.data(), n); - } +inline bool set_socket_opt(socket_t sock, int level, int optname, int optval) { + return set_socket_opt_impl(sock, level, optname, &optval, sizeof(optval)); } -inline void default_socket_options(socket_t sock) { - int yes = 1; +inline bool set_socket_opt_time(socket_t sock, int level, int optname, + time_t sec, time_t usec) { #ifdef _WIN32 - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&yes), sizeof(yes)); - setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, - reinterpret_cast(&yes), sizeof(yes)); + auto timeout = static_cast(sec * 1000 + usec / 1000); #else + timeval timeout; + timeout.tv_sec = static_cast(sec); + timeout.tv_usec = static_cast(usec); +#endif + return set_socket_opt_impl(sock, level, optname, &timeout, sizeof(timeout)); +} + +} // namespace detail + +inline void default_socket_options(socket_t sock) { + detail::set_socket_opt(sock, SOL_SOCKET, #ifdef SO_REUSEPORT - setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, - reinterpret_cast(&yes), sizeof(yes)); + SO_REUSEPORT, #else - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&yes), sizeof(yes)); -#endif + SO_REUSEADDR, #endif + 1); } inline const char *status_message(int status) { @@ -1964,6 +2234,15 @@ inline const char *status_message(int status) { } } +inline std::string get_bearer_token_auth(const Request &req) { + if (req.has_header("Authorization")) { + constexpr auto bearer_header_prefix_len = detail::str_len("Bearer "); + return req.get_header_value("Authorization") + .substr(bearer_header_prefix_len); + } + return ""; +} + template inline Server & Server::set_read_timeout(const std::chrono::duration &duration) { @@ -1991,6 +2270,7 @@ Server::set_idle_interval(const std::chrono::duration &duration) { inline std::string to_string(const Error error) { switch (error) { case Error::Success: return "Success (no error)"; + case Error::Unknown: return "Unknown"; case Error::Connection: return "Could not establish connection"; case Error::BindIPAddress: return "Failed to bind IP address"; case Error::Read: return "Failed to read connection"; @@ -2000,12 +2280,30 @@ inline std::string to_string(const Error error) { case Error::SSLConnection: return "SSL connection failed"; case Error::SSLLoadingCerts: return "SSL certificate loading failed"; case Error::SSLServerVerification: return "SSL server verification failed"; + case Error::SSLServerHostnameVerification: + return "SSL server hostname verification failed"; case Error::UnsupportedMultipartBoundaryChars: return "Unsupported HTTP multipart boundary characters"; case Error::Compression: return "Compression failed"; case Error::ConnectionTimeout: return "Connection timed out"; case Error::ProxyConnection: return "Proxy connection failed"; - case Error::Unknown: return "Unknown"; + case Error::ResourceExhaustion: return "Resource exhaustion"; + case Error::TooManyFormDataFiles: return "Too many form data files"; + case Error::ExceedMaxPayloadSize: return "Exceeded maximum payload size"; + case Error::ExceedUriMaxLength: return "Exceeded maximum URI length"; + case Error::ExceedMaxSocketDescriptorCount: + return "Exceeded maximum socket descriptor count"; + case Error::InvalidRequestLine: return "Invalid request line"; + case Error::InvalidHTTPMethod: return "Invalid HTTP method"; + case Error::InvalidHTTPVersion: return "Invalid HTTP version"; + case Error::InvalidHeaders: return "Invalid headers"; + case Error::MultipartParsing: return "Multipart parsing failed"; + case Error::OpenFile: return "Failed to open file"; + case Error::Listen: return "Failed to listen on socket"; + case Error::GetSockName: return "Failed to get socket name"; + case Error::UnsupportedAddressFamily: return "Unsupported address family"; + case Error::HTTPParsing: return "HTTP parsing failed"; + case Error::InvalidRangeHeader: return "Invalid Range header"; default: break; } @@ -2018,9 +2316,10 @@ inline std::ostream &operator<<(std::ostream &os, const Error &obj) { return os; } -inline uint64_t Result::get_request_header_value_u64(const std::string &key, - size_t id) const { - return detail::get_header_value_u64(request_headers_, key, id, 0); +inline size_t Result::get_request_header_value_u64(const std::string &key, + size_t def, + size_t id) const { + return detail::get_header_value_u64(request_headers_, key, def, id); } template @@ -2045,6 +2344,14 @@ inline void ClientImpl::set_write_timeout( duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); }); } +template +inline void ClientImpl::set_max_timeout( + const std::chrono::duration &duration) { + auto msec = + std::chrono::duration_cast(duration).count(); + set_max_timeout(msec); +} + template inline void Client::set_connection_timeout( const std::chrono::duration &duration) { @@ -2063,6 +2370,16 @@ Client::set_write_timeout(const std::chrono::duration &duration) { cli_->set_write_timeout(duration); } +inline void Client::set_max_timeout(time_t msec) { + cli_->set_max_timeout(msec); +} + +template +inline void +Client::set_max_timeout(const std::chrono::duration &duration) { + cli_->set_max_timeout(duration); +} + /* * Forward declarations and types that will be part of the .h file if split into * .h + .cc. @@ -2072,9 +2389,23 @@ std::string hosted_at(const std::string &hostname); void hosted_at(const std::string &hostname, std::vector &addrs); +// JavaScript-style URL encoding/decoding functions +std::string encode_uri_component(const std::string &value); +std::string encode_uri(const std::string &value); +std::string decode_uri_component(const std::string &value); +std::string decode_uri(const std::string &value); + +// RFC 3986 compliant URL component encoding/decoding functions +std::string encode_path_component(const std::string &component); +std::string decode_path_component(const std::string &component); +std::string encode_query_component(const std::string &component, + bool space_as_plus = true); +std::string decode_query_component(const std::string &component, + bool plus_as_space = true); + std::string append_query_params(const std::string &path, const Params ¶ms); -std::pair make_range_header(Ranges ranges); +std::pair make_range_header(const Ranges &ranges); std::pair make_basic_authentication_header(const std::string &username, @@ -2083,36 +2414,78 @@ make_basic_authentication_header(const std::string &username, namespace detail { -std::string encode_query_param(const std::string &value); +#if defined(_WIN32) +inline std::wstring u8string_to_wstring(const char *s) { + std::wstring ws; + auto len = static_cast(strlen(s)); + auto wlen = ::MultiByteToWideChar(CP_UTF8, 0, s, len, nullptr, 0); + if (wlen > 0) { + ws.resize(wlen); + wlen = ::MultiByteToWideChar( + CP_UTF8, 0, s, len, + const_cast(reinterpret_cast(ws.data())), wlen); + if (wlen != static_cast(ws.size())) { ws.clear(); } + } + return ws; +} +#endif -std::string decode_url(const std::string &s, bool convert_plus_to_space, const std::set &exclude = {}); -void read_file(const std::string &path, std::string &out); +struct FileStat { + FileStat(const std::string &path); + bool is_file() const; + bool is_dir() const; + +private: +#if defined(_WIN32) + struct _stat st_; +#else + struct stat st_; +#endif + int ret_ = -1; +}; std::string trim_copy(const std::string &s); +void divide( + const char *data, std::size_t size, char d, + std::function + fn); + +void divide( + const std::string &str, char d, + std::function + fn); + void split(const char *b, const char *e, char d, std::function fn); void split(const char *b, const char *e, char d, size_t m, std::function 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 callback); - -socket_t create_client_socket( - const std::string &host, const std::string &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); +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, + time_t max_timeout_msec, + std::chrono::time_point start_time, + std::function callback); + +socket_t create_client_socket(const std::string &host, const std::string &ip, + int port, int address_family, bool tcp_nodelay, + bool ipv6_v6only, 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 std::string &key, - size_t id = 0, const char *def = nullptr); + const char *def, size_t id); std::string params_to_query_str(const Params ¶ms); +void parse_query_text(const char *data, std::size_t size, Params ¶ms); + void parse_query_text(const std::string &s, Params ¶ms); bool parse_multipart_boundary(const std::string &content_type, @@ -2120,28 +2493,33 @@ bool parse_multipart_boundary(const std::string &content_type, bool parse_range_header(const std::string &s, Ranges &ranges); +bool parse_accept_header(const std::string &s, + std::vector &content_types); + 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 }; +enum class EncodingType { None = 0, Gzip, Brotli, Zstd }; EncodingType encoding_type(const Request &req, const Response &res); -class BufferStream : public Stream { +class BufferStream final : public Stream { public: BufferStream() = default; ~BufferStream() override = default; bool is_readable() const override; - bool is_writable() const override; + bool wait_readable() const override; + bool wait_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; void get_local_ip_and_port(std::string &ip, int &port) const override; socket_t socket() const override; + time_t duration() const override; const std::string &get_buffer() const; @@ -2170,7 +2548,7 @@ class decompressor { Callback callback) = 0; }; -class nocompressor : public compressor { +class nocompressor final : public compressor { public: ~nocompressor() override = default; @@ -2179,7 +2557,7 @@ class nocompressor : public compressor { }; #ifdef CPPHTTPLIB_ZLIB_SUPPORT -class gzip_compressor : public compressor { +class gzip_compressor final : public compressor { public: gzip_compressor(); ~gzip_compressor() override; @@ -2192,7 +2570,7 @@ class gzip_compressor : public compressor { z_stream strm_; }; -class gzip_decompressor : public decompressor { +class gzip_decompressor final : public decompressor { public: gzip_decompressor(); ~gzip_decompressor() override; @@ -2209,7 +2587,7 @@ class gzip_decompressor : public decompressor { #endif #ifdef CPPHTTPLIB_BROTLI_SUPPORT -class brotli_compressor : public compressor { +class brotli_compressor final : public compressor { public: brotli_compressor(); ~brotli_compressor(); @@ -2221,7 +2599,7 @@ class brotli_compressor : public compressor { BrotliEncoderState *state_ = nullptr; }; -class brotli_decompressor : public decompressor { +class brotli_decompressor final : public decompressor { public: brotli_decompressor(); ~brotli_decompressor(); @@ -2237,6 +2615,34 @@ class brotli_decompressor : public decompressor { }; #endif +#ifdef CPPHTTPLIB_ZSTD_SUPPORT +class zstd_compressor : public compressor { +public: + zstd_compressor(); + ~zstd_compressor(); + + bool compress(const char *data, size_t data_length, bool last, + Callback callback) override; + +private: + ZSTD_CCtx *ctx_ = nullptr; +}; + +class zstd_decompressor : public decompressor { +public: + zstd_decompressor(); + ~zstd_decompressor(); + + bool is_valid() const override; + + bool decompress(const char *data, size_t data_length, + Callback callback) override; + +private: + ZSTD_DCtx *ctx_ = 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 { @@ -2255,7 +2661,7 @@ class stream_line_reader { char *fixed_buffer_; const size_t fixed_buffer_size_; size_t fixed_buffer_used_size_ = 0; - std::string glowable_buffer_; + std::string growable_buffer_; }; class mmap { @@ -2272,27 +2678,82 @@ class mmap { private: #if defined(_WIN32) - HANDLE hFile_; - HANDLE hMapping_; + HANDLE hFile_ = NULL; + HANDLE hMapping_ = NULL; #else - int fd_; + int fd_ = -1; #endif - size_t size_; - void *addr_; + size_t size_ = 0; + void *addr_ = nullptr; + bool is_open_empty_file = false; }; -} // namespace detail +// NOTE: https://www.rfc-editor.org/rfc/rfc9110#section-5 +namespace fields { -// ---------------------------------------------------------------------------- +inline bool is_token_char(char c) { + return std::isalnum(c) || c == '!' || c == '#' || c == '$' || c == '%' || + c == '&' || c == '\'' || c == '*' || c == '+' || c == '-' || + c == '.' || c == '^' || c == '_' || c == '`' || c == '|' || c == '~'; +} -/* - * Implementation that will be part of the .cc file if split into .h + .cc. - */ +inline bool is_token(const std::string &s) { + if (s.empty()) { return false; } + for (auto c : s) { + if (!is_token_char(c)) { return false; } + } + return true; +} -namespace detail { +inline bool is_field_name(const std::string &s) { return is_token(s); } -inline bool is_hex(char c, int &v) { - if (0x20 <= c && isdigit(c)) { +inline bool is_vchar(char c) { return c >= 33 && c <= 126; } + +inline bool is_obs_text(char c) { return 128 <= static_cast(c); } + +inline bool is_field_vchar(char c) { return is_vchar(c) || is_obs_text(c); } + +inline bool is_field_content(const std::string &s) { + if (s.empty()) { return true; } + + if (s.size() == 1) { + return is_field_vchar(s[0]); + } else if (s.size() == 2) { + return is_field_vchar(s[0]) && is_field_vchar(s[1]); + } else { + size_t i = 0; + + if (!is_field_vchar(s[i])) { return false; } + i++; + + while (i < s.size() - 1) { + auto c = s[i++]; + if (c == ' ' || c == '\t' || is_field_vchar(c)) { + } else { + return false; + } + } + + return is_field_vchar(s[i]); + } +} + +inline bool is_field_value(const std::string &s) { return is_field_content(s); } + +} // namespace fields + +} // 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') { @@ -2373,8 +2834,8 @@ inline std::string base64_encode(const std::string &in) { std::string out; out.reserve(in.size()); - unsigned int val = 0; - int valb = -6; + unsigned int val = 0; + int valb = -6; for (auto c : in) { val = (val << 8) + static_cast(c); @@ -2394,20 +2855,6 @@ inline std::string base64_encode(const std::string &in) { 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; @@ -2421,6 +2868,11 @@ inline bool is_valid_path(const std::string &path) { // Read component auto beg = i; while (i < path.size() && path[i] != '/') { + if (path[i] == '\0') { + return false; + } else if (path[i] == '\\') { + return false; + } i++; } @@ -2445,34 +2897,29 @@ inline bool is_valid_path(const std::string &path) { 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(c)) || c == '-' || c == '_' || - c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' || - c == ')') { - escaped << c; - } else { - escaped << std::uppercase; - escaped << '%' << std::setw(2) - << static_cast(static_cast(c)); - escaped << std::nouppercase; - } - } - - return escaped.str(); +inline FileStat::FileStat(const std::string &path) { +#if defined(_WIN32) + auto wpath = u8string_to_wstring(path.c_str()); + ret_ = _wstat(wpath.c_str(), &st_); +#else + ret_ = stat(path.c_str(), &st_); +#endif +} +inline bool FileStat::is_file() const { + return ret_ >= 0 && S_ISREG(st_.st_mode); +} +inline bool FileStat::is_dir() const { + return ret_ >= 0 && S_ISDIR(st_.st_mode); } -inline std::string encode_url(const std::string &s) { +inline std::string encode_path(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; @@ -2497,60 +2944,9 @@ inline std::string encode_url(const std::string &s) { return result; } -inline std::string decode_url(const std::string &s, - bool convert_plus_to_space, - const std::set &exclude) { - std::string result; - - for (size_t i = 0; i < s.size(); i++) { - if (s[i] == '%' && i + 1 < s.size()) { - if (s[i + 1] == 'u') { - auto 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 { - auto val = 0; - if (from_hex_to_i(s, i + 1, 2, val)) { - const auto converted = static_cast(val); - if (exclude.count(converted) == 0) { - result += converted; - } else { - result.append(s, i, 3); - } - 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)); - fs.read(&out[0], static_cast(size)); -} - inline std::string file_extension(const std::string &path) { Match m; - auto re = Regex("\\.([a-zA-Z0-9]+)$"); + thread_local auto re = Regex("\\.([a-zA-Z0-9]+)$"); if (duckdb_re2::RegexSearch(path, m, re)) { return m[1].str(); } return std::string(); } @@ -2580,6 +2976,27 @@ inline std::string trim_double_quotes_copy(const std::string &s) { return s; } +inline void +divide(const char *data, std::size_t size, char d, + std::function + fn) { + const auto it = std::find(data, data + size, d); + const auto found = static_cast(it != data + size); + const auto lhs_data = data; + const auto lhs_size = static_cast(it - data); + const auto rhs_data = it + found; + const auto rhs_size = size - lhs_size - found; + + fn(lhs_data, lhs_size, rhs_data, rhs_size); +} + +inline void +divide(const std::string &str, char d, + std::function + fn) { + divide(str.data(), str.size(), d, std::move(fn)); +} + inline void split(const char *b, const char *e, char d, std::function fn) { return split(b, e, d, static_cast((std::numeric_limits::max)()), fn); @@ -2613,18 +3030,18 @@ inline stream_line_reader::stream_line_reader(Stream &strm, char *fixed_buffer, fixed_buffer_size_(fixed_buffer_size) {} inline const char *stream_line_reader::ptr() const { - if (glowable_buffer_.empty()) { + if (growable_buffer_.empty()) { return fixed_buffer_; } else { - return glowable_buffer_.data(); + return growable_buffer_.data(); } } inline size_t stream_line_reader::size() const { - if (glowable_buffer_.empty()) { + if (growable_buffer_.empty()) { return fixed_buffer_used_size_; } else { - return glowable_buffer_.size(); + return growable_buffer_.size(); } } @@ -2635,9 +3052,18 @@ inline bool stream_line_reader::end_with_crlf() const { inline bool stream_line_reader::getline() { fixed_buffer_used_size_ = 0; - glowable_buffer_.clear(); + growable_buffer_.clear(); + +#ifndef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR + char prev_byte = 0; +#endif for (size_t i = 0;; i++) { + if (size() >= CPPHTTPLIB_MAX_LINE_LENGTH) { + // Treat exceptionally long lines as an error to + // prevent infinite loops/memory exhaustion + return false; + } char byte; auto n = strm_.read(&byte, 1); @@ -2653,7 +3079,12 @@ inline bool stream_line_reader::getline() { append(byte); +#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR if (byte == '\n') { break; } +#else + if (prev_byte == '\r' && byte == '\n') { break; } + prev_byte = byte; +#endif } return true; @@ -2664,24 +3095,15 @@ inline void stream_line_reader::append(char c) { fixed_buffer_[fixed_buffer_used_size_++] = c; fixed_buffer_[fixed_buffer_used_size_] = '\0'; } else { - if (glowable_buffer_.empty()) { + if (growable_buffer_.empty()) { assert(fixed_buffer_[fixed_buffer_used_size_] == '\0'); - glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_); + growable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_); } - glowable_buffer_ += c; + growable_buffer_ += c; } } -inline mmap::mmap(const char *path) -#if defined(_WIN32) - : hFile_(NULL), hMapping_(NULL) -#else - : fd_(-1) -#endif - , - size_(0), addr_(nullptr) { - open(path); -} +inline mmap::mmap(const char *path) { open(path); } inline mmap::~mmap() { close(); } @@ -2689,21 +3111,93 @@ inline bool mmap::open(const char *path) { close(); #if defined(_WIN32) - hFile_ = ::CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); +#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A00 + // Patch for Windows versions < 10 + // used old code from httplib v0.14.3 + + hFile_ = ::CreateFileA( + path, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile_ == INVALID_HANDLE_VALUE) { + return false; + } + + size_ = ::GetFileSize(hFile_, NULL); + + hMapping_ = ::CreateFileMapping( + hFile_, + NULL, + PAGE_READONLY, + 0, + 0, + NULL); + + if (hMapping_ == NULL) { + close(); + return false; + } + + addr_ = ::MapViewOfFile( + hMapping_, + FILE_MAP_READ, + 0, + 0, + 0); + + if (addr_ == NULL) { + close(); + return false; + } + +#else + auto wpath = u8string_to_wstring(path); + if (wpath.empty()) { return false; } + + hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, + OPEN_EXISTING, NULL); if (hFile_ == INVALID_HANDLE_VALUE) { return false; } - size_ = ::GetFileSize(hFile_, NULL); + LARGE_INTEGER size{}; + if (!::GetFileSizeEx(hFile_, &size)) { return false; } + // If the following line doesn't compile due to QuadPart, update Windows SDK. + // See: + // https://github.com/yhirose/cpp-httplib/issues/1903#issuecomment-2316520721 + if (static_cast(size.QuadPart) > + (std::numeric_limits::max)()) { + // `size_t` might be 32-bits, on 32-bits Windows. + return false; + } + size_ = static_cast(size.QuadPart); + + hMapping_ = + ::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL); - hMapping_ = ::CreateFileMapping(hFile_, NULL, PAGE_READONLY, 0, 0, NULL); + // Special treatment for an empty file... + if (hMapping_ == NULL && size_ == 0) { + close(); + is_open_empty_file = true; + return true; + } if (hMapping_ == NULL) { close(); return false; } - addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0); + addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0); + + if (addr_ == nullptr) { + close(); + return false; + } +#endif #else fd_ = ::open(path, O_RDONLY); if (fd_ == -1) { return false; } @@ -2716,21 +3210,27 @@ inline bool mmap::open(const char *path) { size_ = static_cast(sb.st_size); addr_ = ::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0); -#endif - if (addr_ == nullptr) { + // Special treatment for an empty file... + if (addr_ == MAP_FAILED && size_ == 0) { close(); + is_open_empty_file = true; return false; } +#endif return true; } -inline bool mmap::is_open() const { return addr_ != nullptr; } +inline bool mmap::is_open() const { + return is_open_empty_file ? true : addr_ != nullptr; +} inline size_t mmap::size() const { return size_; } -inline const char *mmap::data() const { return (const char *)addr_; } +inline const char *mmap::data() const { + return is_open_empty_file ? "" : static_cast(addr_); +} inline void mmap::close() { #if defined(_WIN32) @@ -2748,6 +3248,8 @@ inline void mmap::close() { ::CloseHandle(hFile_); hFile_ = INVALID_HANDLE_VALUE; } + + is_open_empty_file = false; #else if (addr_ != nullptr) { munmap(addr_, size_); @@ -2773,7 +3275,10 @@ template inline ssize_t handle_EINTR(T fn) { ssize_t res = 0; while (true) { res = fn(); - if (res < 0 && errno == EINTR) { continue; } + if (res < 0 && errno == EINTR) { + std::this_thread::sleep_for(std::chrono::microseconds{1}); + continue; + } break; } return res; @@ -2804,76 +3309,73 @@ inline ssize_t send_socket(socket_t sock, const void *ptr, size_t size, }); } -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(sec * 1000 + usec / 1000); - - return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); +inline int poll_wrapper(struct pollfd *fds, nfds_t nfds, int timeout) { +#ifdef _WIN32 + return ::WSAPoll(fds, nfds, timeout); #else -#ifndef _WIN32 - if (sock >= FD_SETSIZE) { return 1; } + return ::poll(fds, nfds, timeout); #endif +} - fd_set fds; +template +inline ssize_t select_impl(socket_t sock, time_t sec, time_t usec) { +#ifdef __APPLE__ + if (sock >= FD_SETSIZE) { return -1; } + + fd_set fds, *rfds, *wfds; FD_ZERO(&fds); FD_SET(sock, &fds); + rfds = (Read ? &fds : nullptr); + wfds = (Read ? nullptr : &fds); timeval tv; tv.tv_sec = static_cast(sec); tv.tv_usec = static_cast(usec); return handle_EINTR([&]() { - return select(static_cast(sock + 1), &fds, nullptr, nullptr, &tv); + return select(static_cast(sock + 1), rfds, wfds, 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; +#else + struct pollfd pfd; + pfd.fd = sock; + pfd.events = (Read ? POLLIN : POLLOUT); auto timeout = static_cast(sec * 1000 + usec / 1000); - return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); -#else -#ifndef _WIN32 - if (sock >= FD_SETSIZE) { return 1; } + return handle_EINTR([&]() { return poll_wrapper(&pfd, 1, timeout); }); #endif +} - fd_set fds; - FD_ZERO(&fds); - FD_SET(sock, &fds); - - timeval tv; - tv.tv_sec = static_cast(sec); - tv.tv_usec = static_cast(usec); +inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) { + return select_impl(sock, sec, usec); +} - return handle_EINTR([&]() { - return select(static_cast(sock + 1), nullptr, &fds, nullptr, &tv); - }); -#endif +inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) { + return select_impl(sock, sec, usec); } 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; +#ifdef __APPLE__ + if (sock >= FD_SETSIZE) { return Error::Connection; } - auto timeout = static_cast(sec * 1000 + usec / 1000); + fd_set fdsr, fdsw; + FD_ZERO(&fdsr); + FD_ZERO(&fdsw); + FD_SET(sock, &fdsr); + FD_SET(sock, &fdsw); - auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); + timeval tv; + tv.tv_sec = static_cast(sec); + tv.tv_usec = static_cast(usec); - if (poll_res == 0) { return Error::ConnectionTimeout; } + auto ret = handle_EINTR([&]() { + return select(static_cast(sock + 1), &fdsr, &fdsw, nullptr, &tv); + }); - if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) { + if (ret == 0) { return Error::ConnectionTimeout; } + + if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) { auto error = 0; socklen_t len = sizeof(error); auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR, @@ -2884,28 +3386,18 @@ inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, 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; + struct pollfd pfd_read; + pfd_read.fd = sock; + pfd_read.events = POLLIN | POLLOUT; - timeval tv; - tv.tv_sec = static_cast(sec); - tv.tv_usec = static_cast(usec); + auto timeout = static_cast(sec * 1000 + usec / 1000); - auto ret = handle_EINTR([&]() { - return select(static_cast(sock + 1), &fdsr, &fdsw, &fdse, &tv); - }); + auto poll_res = + handle_EINTR([&]() { return poll_wrapper(&pfd_read, 1, timeout); }); - if (ret == 0) { return Error::ConnectionTimeout; } + if (poll_res == 0) { return Error::ConnectionTimeout; } - if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) { + if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) { auto error = 0; socklen_t len = sizeof(error); auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR, @@ -2913,6 +3405,7 @@ inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, auto successful = res >= 0 && !error; return successful ? Error::Success : Error::Connection; } + return Error::Connection; #endif } @@ -2928,19 +3421,24 @@ inline bool is_socket_alive(socket_t sock) { return detail::read_socket(sock, &buf[0], sizeof(buf), MSG_PEEK) > 0; } -class SocketStream : public Stream { +class SocketStream final : 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); + time_t write_timeout_sec, time_t write_timeout_usec, + time_t max_timeout_msec = 0, + std::chrono::time_point start_time = + (std::chrono::steady_clock::time_point::min)()); ~SocketStream() override; bool is_readable() const override; - bool is_writable() const override; + bool wait_readable() const override; + bool wait_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; void get_local_ip_and_port(std::string &ip, int &port) const override; socket_t socket() const override; + time_t duration() const override; private: socket_t sock_; @@ -2948,6 +3446,8 @@ class SocketStream : public Stream { time_t read_timeout_usec_; time_t write_timeout_sec_; time_t write_timeout_usec_; + time_t max_timeout_msec_; + const std::chrono::time_point start_time_; std::vector read_buff_; size_t read_buff_off_ = 0; @@ -2957,20 +3457,25 @@ class SocketStream : public Stream { }; #ifdef CPPHTTPLIB_OPENSSL_SUPPORT -class SSLSocketStream : public Stream { +class SSLSocketStream final : 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( + 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, time_t max_timeout_msec = 0, + std::chrono::time_point start_time = + (std::chrono::steady_clock::time_point::min)()); ~SSLSocketStream() override; bool is_readable() const override; - bool is_writable() const override; + bool wait_readable() const override; + bool wait_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; void get_local_ip_and_port(std::string &ip, int &port) const override; socket_t socket() const override; + time_t duration() const override; private: socket_t sock_; @@ -2979,26 +3484,42 @@ class SSLSocketStream : public Stream { time_t read_timeout_usec_; time_t write_timeout_sec_; time_t write_timeout_usec_; + time_t max_timeout_msec_; + const std::chrono::time_point start_time_; }; #endif -inline bool keep_alive(socket_t sock, time_t keep_alive_timeout_sec) { +inline bool keep_alive(const std::atomic &svr_sock, socket_t sock, + time_t keep_alive_timeout_sec) { using namespace std::chrono; - auto start = steady_clock::now(); + + const auto interval_usec = + CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND; + + // Avoid expensive `steady_clock::now()` call for the first time + if (select_read(sock, 0, interval_usec) > 0) { return true; } + + const auto start = steady_clock::now() - microseconds{interval_usec}; + const auto timeout = seconds{keep_alive_timeout_sec}; + while (true) { - auto val = select_read(sock, 0, 10000); + if (svr_sock == INVALID_SOCKET) { + break; // Server socket is closed + } + + auto val = select_read(sock, 0, interval_usec); if (val < 0) { - return false; + break; // Ssocket error } else if (val == 0) { - auto current = steady_clock::now(); - auto duration = duration_cast(current - start); - auto timeout = keep_alive_timeout_sec * 1000; - if (duration.count() > timeout) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (steady_clock::now() - start > timeout) { + break; // Timeout + } } else { - return true; + return true; // Ready for read } } + + return false; } template @@ -3009,8 +3530,7 @@ process_server_socket_core(const std::atomic &svr_sock, socket_t sock, 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)) { + while (count > 0 && keep_alive(svr_sock, sock, keep_alive_timeout_sec)) { auto close_connection = count == 1; auto connection_closed = false; ret = callback(close_connection, connection_closed); @@ -3036,13 +3556,15 @@ process_server_socket(const std::atomic &svr_sock, socket_t sock, }); } -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 callback) { +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, + time_t max_timeout_msec, + std::chrono::time_point start_time, + std::function callback) { SocketStream strm(sock, read_timeout_sec, read_timeout_usec, - write_timeout_sec, write_timeout_usec); + write_timeout_sec, write_timeout_usec, max_timeout_msec, + start_time); return callback(strm); } @@ -3054,50 +3576,417 @@ inline int shutdown_socket(socket_t sock) { #endif } -template -socket_t create_socket(const std::string &host, const std::string &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; +inline std::string escape_abstract_namespace_unix_domain(const std::string &s) { + if (s.size() > 1 && s[0] == '\0') { + auto ret = s; + ret[0] = '@'; + return ret; + } + return s; +} - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; +inline std::string +unescape_abstract_namespace_unix_domain(const std::string &s) { + if (s.size() > 1 && s[0] == '@') { + auto ret = s; + ret[0] = '\0'; + return ret; + } + return s; +} - if (!ip.empty()) { - node = ip.c_str(); - // Ask getaddrinfo to convert IP in c-string to address - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_NUMERICHOST; - } else { - if (!host.empty()) { node = host.c_str(); } - hints.ai_family = address_family; - hints.ai_flags = socket_flags; +inline int getaddrinfo_with_timeout(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res, time_t timeout_sec) { +#ifdef CPPHTTPLIB_USE_NON_BLOCKING_GETADDRINFO + if (timeout_sec <= 0) { + // No timeout specified, use standard getaddrinfo + return getaddrinfo(node, service, hints, res); } -#ifndef _WIN32 - if (hints.ai_family == AF_UNIX) { +#ifdef _WIN32 + // Windows-specific implementation using GetAddrInfoEx with overlapped I/O + OVERLAPPED overlapped = {0}; + HANDLE event = CreateEventW(nullptr, TRUE, FALSE, nullptr); + if (!event) { return EAI_FAIL; } + + overlapped.hEvent = event; + + PADDRINFOEXW result_addrinfo = nullptr; + HANDLE cancel_handle = nullptr; + + ADDRINFOEXW hints_ex = {0}; + if (hints) { + hints_ex.ai_flags = hints->ai_flags; + hints_ex.ai_family = hints->ai_family; + hints_ex.ai_socktype = hints->ai_socktype; + hints_ex.ai_protocol = hints->ai_protocol; + } + + auto wnode = u8string_to_wstring(node); + auto wservice = u8string_to_wstring(service); + + auto ret = ::GetAddrInfoExW(wnode.data(), wservice.data(), NS_DNS, nullptr, + hints ? &hints_ex : nullptr, &result_addrinfo, + nullptr, &overlapped, nullptr, &cancel_handle); + + if (ret == WSA_IO_PENDING) { + auto wait_result = + ::WaitForSingleObject(event, static_cast(timeout_sec * 1000)); + if (wait_result == WAIT_TIMEOUT) { + if (cancel_handle) { ::GetAddrInfoExCancel(&cancel_handle); } + ::CloseHandle(event); + return EAI_AGAIN; + } + + DWORD bytes_returned; + if (!::GetOverlappedResult((HANDLE)INVALID_SOCKET, &overlapped, + &bytes_returned, FALSE)) { + ::CloseHandle(event); + return ::WSAGetLastError(); + } + } + + ::CloseHandle(event); + + if (ret == NO_ERROR || ret == WSA_IO_PENDING) { + *res = reinterpret_cast(result_addrinfo); + return 0; + } + + return ret; +#elif TARGET_OS_MAC + // macOS implementation using CFHost API for asynchronous DNS resolution + CFStringRef hostname_ref = CFStringCreateWithCString( + kCFAllocatorDefault, node, kCFStringEncodingUTF8); + if (!hostname_ref) { return EAI_MEMORY; } + + CFHostRef host_ref = CFHostCreateWithName(kCFAllocatorDefault, hostname_ref); + CFRelease(hostname_ref); + if (!host_ref) { return EAI_MEMORY; } + + // Set up context for callback + struct CFHostContext { + bool completed = false; + bool success = false; + CFArrayRef addresses = nullptr; + std::mutex mutex; + std::condition_variable cv; + } context; + + CFHostClientContext client_context; + memset(&client_context, 0, sizeof(client_context)); + client_context.info = &context; + + // Set callback + auto callback = [](CFHostRef theHost, CFHostInfoType /*typeInfo*/, + const CFStreamError *error, void *info) { + auto ctx = static_cast(info); + std::lock_guard lock(ctx->mutex); + + if (error && error->error != 0) { + ctx->success = false; + } else { + Boolean hasBeenResolved; + ctx->addresses = CFHostGetAddressing(theHost, &hasBeenResolved); + if (ctx->addresses && hasBeenResolved) { + CFRetain(ctx->addresses); + ctx->success = true; + } else { + ctx->success = false; + } + } + ctx->completed = true; + ctx->cv.notify_one(); + }; + + if (!CFHostSetClient(host_ref, callback, &client_context)) { + CFRelease(host_ref); + return EAI_SYSTEM; + } + + // Schedule on run loop + CFRunLoopRef run_loop = CFRunLoopGetCurrent(); + CFHostScheduleWithRunLoop(host_ref, run_loop, kCFRunLoopDefaultMode); + + // Start resolution + CFStreamError stream_error; + if (!CFHostStartInfoResolution(host_ref, kCFHostAddresses, &stream_error)) { + CFHostUnscheduleFromRunLoop(host_ref, run_loop, kCFRunLoopDefaultMode); + CFRelease(host_ref); + return EAI_FAIL; + } + + // Wait for completion with timeout + auto timeout_time = + std::chrono::steady_clock::now() + std::chrono::seconds(timeout_sec); + bool timed_out = false; + + { + duckdb::unique_lock lock(context.mutex); + + while (!context.completed) { + auto now = std::chrono::steady_clock::now(); + if (now >= timeout_time) { + timed_out = true; + break; + } + + // Run the runloop for a short time + lock.unlock(); + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, true); + lock.lock(); + } + } + + // Clean up + CFHostUnscheduleFromRunLoop(host_ref, run_loop, kCFRunLoopDefaultMode); + CFHostSetClient(host_ref, nullptr, nullptr); + + if (timed_out || !context.completed) { + CFHostCancelInfoResolution(host_ref, kCFHostAddresses); + CFRelease(host_ref); + return EAI_AGAIN; + } + + if (!context.success || !context.addresses) { + CFRelease(host_ref); + return EAI_NODATA; + } + + // Convert CFArray to addrinfo + CFIndex count = CFArrayGetCount(context.addresses); + if (count == 0) { + CFRelease(context.addresses); + CFRelease(host_ref); + return EAI_NODATA; + } + + struct addrinfo *result_addrinfo = nullptr; + struct addrinfo **current = &result_addrinfo; + + for (CFIndex i = 0; i < count; i++) { + CFDataRef addr_data = + static_cast(CFArrayGetValueAtIndex(context.addresses, i)); + if (!addr_data) continue; + + const struct sockaddr *sockaddr_ptr = + reinterpret_cast(CFDataGetBytePtr(addr_data)); + socklen_t sockaddr_len = static_cast(CFDataGetLength(addr_data)); + + // Allocate addrinfo structure + *current = static_cast(malloc(sizeof(struct addrinfo))); + if (!*current) { + freeaddrinfo(result_addrinfo); + CFRelease(context.addresses); + CFRelease(host_ref); + return EAI_MEMORY; + } + + memset(*current, 0, sizeof(struct addrinfo)); + + // Set up addrinfo fields + (*current)->ai_family = sockaddr_ptr->sa_family; + (*current)->ai_socktype = hints ? hints->ai_socktype : SOCK_STREAM; + (*current)->ai_protocol = hints ? hints->ai_protocol : IPPROTO_TCP; + (*current)->ai_addrlen = sockaddr_len; + + // Copy sockaddr + (*current)->ai_addr = static_cast(malloc(sockaddr_len)); + if (!(*current)->ai_addr) { + freeaddrinfo(result_addrinfo); + CFRelease(context.addresses); + CFRelease(host_ref); + return EAI_MEMORY; + } + memcpy((*current)->ai_addr, sockaddr_ptr, sockaddr_len); + + // Set port if service is specified + if (service && strlen(service) > 0) { + int port = atoi(service); + if (port > 0) { + if (sockaddr_ptr->sa_family == AF_INET) { + reinterpret_cast((*current)->ai_addr) + ->sin_port = htons(static_cast(port)); + } else if (sockaddr_ptr->sa_family == AF_INET6) { + reinterpret_cast((*current)->ai_addr) + ->sin6_port = htons(static_cast(port)); + } + } + } + + current = &((*current)->ai_next); + } + + CFRelease(context.addresses); + CFRelease(host_ref); + + *res = result_addrinfo; + return 0; +#elif defined(_GNU_SOURCE) && defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) + // Linux implementation using getaddrinfo_a for asynchronous DNS resolution + struct gaicb request; + struct gaicb *requests[1] = {&request}; + struct sigevent sevp; + struct timespec timeout; + + // Initialize the request structure + memset(&request, 0, sizeof(request)); + request.ar_name = node; + request.ar_service = service; + request.ar_request = hints; + + // Set up timeout + timeout.tv_sec = timeout_sec; + timeout.tv_nsec = 0; + + // Initialize sigevent structure (not used, but required) + memset(&sevp, 0, sizeof(sevp)); + sevp.sigev_notify = SIGEV_NONE; + + // Start asynchronous resolution + int start_result = getaddrinfo_a(GAI_NOWAIT, requests, 1, &sevp); + if (start_result != 0) { return start_result; } + + // Wait for completion with timeout + int wait_result = + gai_suspend((const struct gaicb *const *)requests, 1, &timeout); + + if (wait_result == 0 || wait_result == EAI_ALLDONE) { + // Completed successfully, get the result + int gai_result = gai_error(&request); + if (gai_result == 0) { + *res = request.ar_result; + return 0; + } else { + // Clean up on error + if (request.ar_result) { freeaddrinfo(request.ar_result); } + return gai_result; + } + } else if (wait_result == EAI_AGAIN) { + // Timeout occurred, cancel the request + gai_cancel(&request); + return EAI_AGAIN; + } else { + // Other error occurred + gai_cancel(&request); + return wait_result; + } +#else + // Fallback implementation using thread-based timeout for other Unix systems + + struct GetAddrInfoState { + std::mutex mutex; + std::condition_variable result_cv; + bool completed = false; + int result = EAI_SYSTEM; + std::string node = node; + std::string service = service; + struct addrinfo hints = hints; + struct addrinfo *info = nullptr; + }; + + // Allocate on the heap, so the resolver thread can keep using the data. + auto state = duckdb::make_shared_ptr(); + + std::thread resolve_thread([=]() { + auto thread_result = getaddrinfo( + state->node.c_str(), state->service.c_str(), hints, &state->info); + + std::lock_guard lock(state->mutex); + state->result = thread_result; + state->completed = true; + state->result_cv.notify_one(); + }); + + // Wait for completion or timeout + duckdb::unique_lock lock(state->mutex); + auto finished = + state->result_cv.wait_for(lock, std::chrono::seconds(timeout_sec), + [&] { return state->completed; }); + + if (finished) { + // Operation completed within timeout + resolve_thread.join(); + *res = state->info; + return state->result; + } else { + // Timeout occurred + resolve_thread.detach(); // Let the thread finish in background + return EAI_AGAIN; // Return timeout error + } +#endif +#else + (void)(timeout_sec); // Unused parameter for non-blocking getaddrinfo + return getaddrinfo(node, service, hints, res); +#endif +} + +template +socket_t create_socket(const std::string &host, const std::string &ip, int port, + int address_family, int socket_flags, bool tcp_nodelay, + bool ipv6_v6only, SocketOptions socket_options, + BindOrConnect bind_or_connect, time_t timeout_sec = 0) { + // 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 = IPPROTO_IP; + + if (!ip.empty()) { + node = ip.c_str(); + // Ask getaddrinfo to convert IP in c-string to address + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + } else { + if (!host.empty()) { node = host.c_str(); } + hints.ai_family = address_family; + hints.ai_flags = socket_flags; + } + +#if !defined(_WIN32) || defined(CPPHTTPLIB_HAVE_AFUNIX_H) + if (hints.ai_family == AF_UNIX) { const auto addrlen = host.length(); if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; } +#ifdef SOCK_CLOEXEC + auto sock = socket(hints.ai_family, hints.ai_socktype | SOCK_CLOEXEC, + hints.ai_protocol); +#else auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol); +#endif + if (sock != INVALID_SOCKET) { sockaddr_un addr{}; addr.sun_family = AF_UNIX; - std::copy(host.begin(), host.end(), addr.sun_path); + + auto unescaped_host = unescape_abstract_namespace_unix_domain(host); + std::copy(unescaped_host.begin(), unescaped_host.end(), addr.sun_path); hints.ai_addr = reinterpret_cast(&addr); hints.ai_addrlen = static_cast( sizeof(addr) - sizeof(addr.sun_path) + addrlen); +#ifndef SOCK_CLOEXEC +#ifndef _WIN32 fcntl(sock, F_SETFD, FD_CLOEXEC); +#endif +#endif + if (socket_options) { socket_options(sock); } - if (!bind_or_connect(sock, hints)) { +#ifdef _WIN32 + // Setting SO_REUSEADDR seems not to work well with AF_UNIX on windows, so + // remove the option. + detail::set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 0); +#endif + + bool dummy; + if (!bind_or_connect(sock, hints, dummy)) { close_socket(sock); sock = INVALID_SOCKET; } @@ -3108,12 +3997,14 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port, auto service = std::to_string(port); - if (getaddrinfo(node, service.c_str(), &hints, &result)) { + if (getaddrinfo_with_timeout(node, service.c_str(), &hints, &result, + timeout_sec)) { #if defined __linux__ && !defined __ANDROID__ res_init(); #endif return INVALID_SOCKET; } + auto se = detail::scope_exit([&] { freeaddrinfo(result); }); for (auto rp = result; rp; rp = rp->ai_next) { // Create a socket @@ -3139,51 +4030,41 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port, sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); } #else + +#ifdef SOCK_CLOEXEC + auto sock = + socket(rp->ai_family, rp->ai_socktype | SOCK_CLOEXEC, rp->ai_protocol); +#else auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); +#endif + #endif if (sock == INVALID_SOCKET) { continue; } -#ifndef _WIN32 +#if !defined _WIN32 && !defined SOCK_CLOEXEC if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { close_socket(sock); continue; } #endif - if (tcp_nodelay) { - auto yes = 1; -#ifdef _WIN32 - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&yes), sizeof(yes)); -#else - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&yes), sizeof(yes)); -#endif - } - - if (socket_options) { socket_options(sock); } + if (tcp_nodelay) { set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1); } if (rp->ai_family == AF_INET6) { - auto no = 0; -#ifdef _WIN32 - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - reinterpret_cast(&no), sizeof(no)); -#else - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - reinterpret_cast(&no), sizeof(no)); -#endif + set_socket_opt(sock, IPPROTO_IPV6, IPV6_V6ONLY, ipv6_v6only ? 1 : 0); } + if (socket_options) { socket_options(sock); } + // bind or connect - if (bind_or_connect(sock, *rp)) { - freeaddrinfo(result); - return sock; - } + auto quit = false; + if (bind_or_connect(sock, *rp, quit)) { return sock; } close_socket(sock); + + if (quit) { break; } } - freeaddrinfo(result); return INVALID_SOCKET; } @@ -3215,7 +4096,11 @@ inline bool bind_ip_address(socket_t sock, const std::string &host) { hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; - if (getaddrinfo(host.c_str(), "0", &hints, &result)) { return false; } + if (getaddrinfo_with_timeout(host.c_str(), "0", &hints, &result, 0)) { + return false; + } + + auto se = detail::scope_exit([&] { freeaddrinfo(result); }); auto ret = false; for (auto rp = result; rp; rp = rp->ai_next) { @@ -3226,7 +4111,6 @@ inline bool bind_ip_address(socket_t sock, const std::string &host) { } } - freeaddrinfo(result); return ret; } @@ -3238,6 +4122,8 @@ inline bool bind_ip_address(socket_t sock, const std::string &host) { inline std::string if2ip(int address_family, const std::string &ifn) { struct ifaddrs *ifap; getifaddrs(&ifap); + auto se = detail::scope_exit([&] { freeifaddrs(ifap); }); + std::string addr_candidate; for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr && ifn == ifa->ifa_name && @@ -3247,7 +4133,6 @@ inline std::string if2ip(int address_family, const std::string &ifn) { auto sa = reinterpret_cast(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); } } else if (ifa->ifa_addr->sa_family == AF_INET6) { @@ -3260,7 +4145,6 @@ inline std::string if2ip(int address_family, const std::string &ifn) { if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) { addr_candidate = std::string(buf, INET6_ADDRSTRLEN); } else { - freeifaddrs(ifap); return std::string(buf, INET6_ADDRSTRLEN); } } @@ -3268,20 +4152,21 @@ inline std::string if2ip(int address_family, const std::string &ifn) { } } } - freeifaddrs(ifap); return addr_candidate; } #endif inline socket_t create_client_socket( const std::string &host, const std::string &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, + int address_family, bool tcp_nodelay, bool ipv6_v6only, + 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 { + host, ip, port, address_family, 0, tcp_nodelay, ipv6_v6only, + std::move(socket_options), + [&](socket_t sock2, struct addrinfo &ai, bool &quit) -> bool { if (!intf.empty()) { #ifdef USE_IF2IP auto ip_from_if = if2ip(address_family, intf); @@ -3305,44 +4190,22 @@ inline socket_t create_client_socket( } error = wait_until_socket_is_ready(sock2, connection_timeout_sec, connection_timeout_usec); - if (error != Error::Success) { return false; } + if (error != Error::Success) { + if (error == Error::ConnectionTimeout) { quit = true; } + return false; + } } set_nonblocking(sock2, false); - - { -#ifdef _WIN32 - auto timeout = static_cast(read_timeout_sec * 1000 + - read_timeout_usec / 1000); - setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&timeout), sizeof(timeout)); -#else - timeval tv; - tv.tv_sec = static_cast(read_timeout_sec); - tv.tv_usec = static_cast(read_timeout_usec); - setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&tv), sizeof(tv)); -#endif - } - { - -#ifdef _WIN32 - auto timeout = static_cast(write_timeout_sec * 1000 + - write_timeout_usec / 1000); - setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, - reinterpret_cast(&timeout), sizeof(timeout)); -#else - timeval tv; - tv.tv_sec = static_cast(write_timeout_sec); - tv.tv_usec = static_cast(write_timeout_usec); - setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, - reinterpret_cast(&tv), sizeof(tv)); -#endif - } + set_socket_opt_time(sock2, SOL_SOCKET, SO_RCVTIMEO, read_timeout_sec, + read_timeout_usec); + set_socket_opt_time(sock2, SOL_SOCKET, SO_SNDTIMEO, write_timeout_sec, + write_timeout_usec); error = Error::Success; return true; - }); + }, + connection_timeout_sec); // Pass DNS timeout if (sock != INVALID_SOCKET) { error = Error::Success; @@ -3398,7 +4261,7 @@ inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) { if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0) { port = ucred.pid; } -#elif defined(SOL_LOCAL) && defined(SO_PEERPID) // __APPLE__ +#elif defined(SOL_LOCAL) && defined(SO_PEERPID) pid_t pid; socklen_t len = sizeof(pid); if (getsockopt(sock, SOL_LOCAL, SO_PEERPID, &pid, &len) == 0) { @@ -3431,7 +4294,7 @@ inline unsigned int str2tag(const std::string &s) { namespace udl { inline constexpr unsigned int operator ""_t(const char *s, size_t l) { - return str2tag_core(s, l, 0); + return str2tag_core(s, l, 0); } } // namespace udl @@ -3515,8 +4378,9 @@ inline bool can_compress_content_type(const std::string &content_type) { case "application/protobuf"_t: case "application/xhtml+xml"_t: return true; - default: - return !content_type.rfind("text/", 0) && tag != "text/event-stream"_t; + case "text/event-stream"_t: return false; + + default: return !content_type.rfind("text/", 0); } } @@ -3540,6 +4404,12 @@ inline EncodingType encoding_type(const Request &req, const Response &res) { if (ret) { return EncodingType::Gzip; } #endif +#ifdef CPPHTTPLIB_ZSTD_SUPPORT + // TODO: 'Accept-Encoding' has zstd, not zstd;q=0 + ret = s.find("zstd") != std::string::npos; + if (ret) { return EncodingType::Zstd; } +#endif + return EncodingType::None; } @@ -3748,13 +4618,90 @@ inline bool brotli_decompressor::decompress(const char *data, } #endif +#ifdef CPPHTTPLIB_ZSTD_SUPPORT +inline zstd_compressor::zstd_compressor() { + ctx_ = ZSTD_createCCtx(); + ZSTD_CCtx_setParameter(ctx_, ZSTD_c_compressionLevel, ZSTD_fast); +} + +inline zstd_compressor::~zstd_compressor() { ZSTD_freeCCtx(ctx_); } + +inline bool zstd_compressor::compress(const char *data, size_t data_length, + bool last, Callback callback) { + std::array buff{}; + + ZSTD_EndDirective mode = last ? ZSTD_e_end : ZSTD_e_continue; + ZSTD_inBuffer input = {data, data_length, 0}; + + bool finished; + do { + ZSTD_outBuffer output = {buff.data(), CPPHTTPLIB_COMPRESSION_BUFSIZ, 0}; + size_t const remaining = ZSTD_compressStream2(ctx_, &output, &input, mode); + + if (ZSTD_isError(remaining)) { return false; } + + if (!callback(buff.data(), output.pos)) { return false; } + + finished = last ? (remaining == 0) : (input.pos == input.size); + + } while (!finished); + + return true; +} + +inline zstd_decompressor::zstd_decompressor() { ctx_ = ZSTD_createDCtx(); } + +inline zstd_decompressor::~zstd_decompressor() { ZSTD_freeDCtx(ctx_); } + +inline bool zstd_decompressor::is_valid() const { return ctx_ != nullptr; } + +inline bool zstd_decompressor::decompress(const char *data, size_t data_length, + Callback callback) { + std::array buff{}; + ZSTD_inBuffer input = {data, data_length, 0}; + + while (input.pos < input.size) { + ZSTD_outBuffer output = {buff.data(), CPPHTTPLIB_COMPRESSION_BUFSIZ, 0}; + size_t const remaining = ZSTD_decompressStream(ctx_, &output, &input); + + if (ZSTD_isError(remaining)) { return false; } + + if (!callback(buff.data(), output.pos)) { return false; } + } + + return true; +} +#endif + +inline bool is_prohibited_header_name(const std::string &name) { + using udl::operator""_t; + + switch (str2tag(name)) { + case "REMOTE_ADDR"_t: + case "REMOTE_PORT"_t: + case "LOCAL_ADDR"_t: + case "LOCAL_PORT"_t: return true; + default: return false; + } +} + inline bool has_header(const Headers &headers, const std::string &key) { + if (is_prohibited_header_name(key)) { return false; } return headers.find(key) != headers.end(); } inline const char *get_header_value(const Headers &headers, - const std::string &key, size_t id, - const char *def) { + const std::string &key, const char *def, + size_t id) { + if (is_prohibited_header_name(key)) { +#ifndef CPPHTTPLIB_NO_EXCEPTIONS + std::string msg = "Prohibited header name '" + key + "' is specified."; + throw std::invalid_argument(msg); +#else + return ""; +#endif + } + auto rng = headers.equal_range(key); auto it = rng.first; std::advance(it, static_cast(id)); @@ -3762,14 +4709,6 @@ inline const char *get_header_value(const Headers &headers, return def; } -inline bool compare_case_ignore(const std::string &a, const std::string &b) { - 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; -} - template inline bool parse_header(const char *beg, const char *end, T fn) { // Skip trailing spaces and tabs. @@ -3782,6 +4721,9 @@ inline bool parse_header(const char *beg, const char *end, T fn) { p++; } + auto name = std::string(beg, p); + if (!detail::fields::is_field_name(name)) { return false; } + if (p == end) { return false; } auto key_end = p; @@ -3792,15 +4734,22 @@ inline bool parse_header(const char *beg, const char *end, T fn) { p++; } - if (p < end) { + if (p <= end) { auto key_len = key_end - beg; if (!key_len) { return false; } auto key = std::string(beg, key_end); - auto val = compare_case_ignore(key, "Location") || compare_case_ignore(key, "Link") - ? std::string(p, end) - : decode_url(std::string(p, end), false); - fn(std::move(key), std::move(val)); + auto val = std::string(p, end); + + if (!detail::fields::is_field_value(val)) { return false; } + + if (case_ignore::equal(key, "Location") || + case_ignore::equal(key, "Referer")) { + fn(key, val); + } else { + fn(key, decode_path_component(val)); + } + return true; } @@ -3812,6 +4761,8 @@ inline bool read_headers(Stream &strm, Headers &headers) { char buf[bufsiz]; stream_line_reader line_reader(strm, buf, bufsiz); + size_t header_count = 0; + for (;;) { if (!line_reader.getline()) { return false; } @@ -3820,45 +4771,50 @@ inline bool read_headers(Stream &strm, Headers &headers) { 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 { +#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR // 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; } + // Check header count limit + if (header_count >= CPPHTTPLIB_HEADER_MAX_COUNT) { 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)); - }); + if (!parse_header(line_reader.ptr(), end, + [&](const std::string &key, const std::string &val) { + headers.emplace(key, val); + })) { + return false; + } + + header_count++; } return true; } -inline bool read_content_with_length(Stream &strm, uint64_t len, - Progress progress, +inline bool read_content_with_length(Stream &strm, size_t len, + DownloadProgress progress, ContentReceiverWithProgress out) { char buf[CPPHTTPLIB_RECV_BUFSIZ]; - uint64_t r = 0; + size_t r = 0; while (r < len) { auto read_len = static_cast(len - r); auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ)); if (n <= 0) { return false; } if (!out(buf, static_cast(n), r, len)) { return false; } - r += static_cast(n); + r += static_cast(n); if (progress) { if (!progress(r, len)) { return false; } @@ -3868,90 +4824,176 @@ inline bool read_content_with_length(Stream &strm, uint64_t len, return true; } -inline void skip_content_with_length(Stream &strm, uint64_t len) { +inline void skip_content_with_length(Stream &strm, size_t len) { char buf[CPPHTTPLIB_RECV_BUFSIZ]; - uint64_t r = 0; + size_t r = 0; while (r < len) { auto read_len = static_cast(len - r); auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ)); if (n <= 0) { return; } - r += static_cast(n); + r += static_cast(n); } } -inline bool read_content_without_length(Stream &strm, - ContentReceiverWithProgress out) { +enum class ReadContentResult { + Success, // Successfully read the content + PayloadTooLarge, // The content exceeds the specified payload limit + Error // An error occurred while reading the content +}; + +inline ReadContentResult +read_content_without_length(Stream &strm, size_t payload_max_length, + ContentReceiverWithProgress out) { char buf[CPPHTTPLIB_RECV_BUFSIZ]; - uint64_t r = 0; + size_t r = 0; for (;;) { auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ); - if (n <= 0) { return true; } + if (n == 0) { return ReadContentResult::Success; } + if (n < 0) { return ReadContentResult::Error; } + + // Check if adding this data would exceed the payload limit + if (r > payload_max_length || + payload_max_length - r < static_cast(n)) { + return ReadContentResult::PayloadTooLarge; + } - if (!out(buf, static_cast(n), r, 0)) { return false; } - r += static_cast(n); + if (!out(buf, static_cast(n), r, 0)) { + return ReadContentResult::Error; + } + r += static_cast(n); } - return true; + return ReadContentResult::Success; } template -inline bool read_content_chunked(Stream &strm, T &x, - ContentReceiverWithProgress out) { +inline ReadContentResult read_content_chunked(Stream &strm, T &x, + size_t payload_max_length, + ContentReceiverWithProgress out) { const auto bufsiz = 16; char buf[bufsiz]; stream_line_reader line_reader(strm, buf, bufsiz); - if (!line_reader.getline()) { return false; } + if (!line_reader.getline()) { return ReadContentResult::Error; } unsigned long chunk_len; + size_t total_len = 0; 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 (end_ptr == line_reader.ptr()) { return ReadContentResult::Error; } + if (chunk_len == ULONG_MAX) { return ReadContentResult::Error; } if (chunk_len == 0) { break; } + // Check if adding this chunk would exceed the payload limit + if (total_len > payload_max_length || + payload_max_length - total_len < chunk_len) { + return ReadContentResult::PayloadTooLarge; + } + + total_len += chunk_len; + if (!read_content_with_length(strm, chunk_len, nullptr, out)) { - return false; + return ReadContentResult::Error; } - if (!line_reader.getline()) { return false; } + if (!line_reader.getline()) { return ReadContentResult::Error; } - if (strcmp(line_reader.ptr(), "\r\n") != 0) { return false; } + if (strcmp(line_reader.ptr(), "\r\n") != 0) { + return ReadContentResult::Error; + } - if (!line_reader.getline()) { return false; } + if (!line_reader.getline()) { return ReadContentResult::Error; } } assert(chunk_len == 0); - // Trailer - if (!line_reader.getline()) { return false; } + // NOTE: In RFC 9112, '7.1 Chunked Transfer Coding' mentions "The chunked + // transfer coding is complete when a chunk with a chunk-size of zero is + // received, possibly followed by a trailer section, and finally terminated by + // an empty line". https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1 + // + // In '7.1.3. Decoding Chunked', however, the pseudo-code in the section + // does't care for the existence of the final CRLF. In other words, it seems + // to be ok whether the final CRLF exists or not in the chunked data. + // https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1.3 + // + // According to the reference code in RFC 9112, cpp-httplib now allows + // chunked transfer coding data without the final CRLF. + if (!line_reader.getline()) { return ReadContentResult::Success; } + + // RFC 7230 Section 4.1.2 - Headers prohibited in trailers + thread_local case_ignore::unordered_set prohibited_trailers = { + // Message framing + "transfer-encoding", "content-length", + + // Routing + "host", + + // Authentication + "authorization", "www-authenticate", "proxy-authenticate", + "proxy-authorization", "cookie", "set-cookie", + + // Request modifiers + "cache-control", "expect", "max-forwards", "pragma", "range", "te", + + // Response control + "age", "expires", "date", "location", "retry-after", "vary", "warning", + + // Payload processing + "content-encoding", "content-type", "content-range", "trailer"}; + + // Parse declared trailer headers once for performance + case_ignore::unordered_set declared_trailers; + if (has_header(x.headers, "Trailer")) { + auto trailer_header = get_header_value(x.headers, "Trailer", "", 0); + auto len = std::strlen(trailer_header); + + split(trailer_header, trailer_header + len, ',', + [&](const char *b, const char *e) { + std::string key(b, e); + if (prohibited_trailers.find(key) == prohibited_trailers.end()) { + declared_trailers.insert(key); + } + }); + } + size_t trailer_header_count = 0; while (strcmp(line_reader.ptr(), "\r\n") != 0) { - if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } + if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { + return ReadContentResult::Error; + } + + // Check trailer header count limit + if (trailer_header_count >= CPPHTTPLIB_HEADER_MAX_COUNT) { + return ReadContentResult::Error; + } // Exclude line terminator constexpr auto line_terminator_len = 2; auto end = line_reader.ptr() + line_reader.size() - line_terminator_len; parse_header(line_reader.ptr(), end, - [&](std::string &&key, std::string &&val) { - x.headers.emplace(std::move(key), std::move(val)); + [&](const std::string &key, const std::string &val) { + if (declared_trailers.find(key) != declared_trailers.end()) { + x.trailers.emplace(key, val); + trailer_header_count++; + } }); - if (!line_reader.getline()) { return false; } + if (!line_reader.getline()) { return ReadContentResult::Error; } } - return true; + return ReadContentResult::Success; } inline bool is_chunked_transfer_encoding(const Headers &headers) { - return !strcasecmp(get_header_value(headers, "Transfer-Encoding", 0, ""), - "chunked"); + return case_ignore::equal( + get_header_value(headers, "Transfer-Encoding", "", 0), "chunked"); } template @@ -3975,13 +5017,20 @@ bool prepare_content_receiver(T &x, int &status, #else status = StatusCode::UnsupportedMediaType_415; return false; +#endif + } else if (encoding == "zstd") { +#ifdef CPPHTTPLIB_ZSTD_SUPPORT + decompressor = detail::make_unique(); +#else + status = StatusCode::UnsupportedMediaType_415; + return false; #endif } if (decompressor) { if (decompressor->is_valid()) { ContentReceiverWithProgress out = [&](const char *buf, size_t n, - uint64_t off, uint64_t len) { + size_t off, size_t len) { return decompressor->decompress(buf, n, [&](const char *buf2, size_t n2) { return receiver(buf2, n2, off, len); @@ -3995,8 +5044,8 @@ bool prepare_content_receiver(T &x, int &status, } } - ContentReceiverWithProgress out = [&](const char *buf, size_t n, uint64_t off, - uint64_t len) { + ContentReceiverWithProgress out = [&](const char *buf, size_t n, size_t off, + size_t len) { return receiver(buf, n, off, len); }; return callback(std::move(out)); @@ -4004,8 +5053,8 @@ bool prepare_content_receiver(T &x, int &status, template bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status, - Progress progress, ContentReceiverWithProgress receiver, - bool decompress) { + DownloadProgress progress, + ContentReceiverWithProgress receiver, bool decompress) { return prepare_content_receiver( x, status, std::move(receiver), decompress, [&](const ContentReceiverWithProgress &out) { @@ -4013,19 +5062,42 @@ bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status, auto exceed_payload_max_length = false; if (is_chunked_transfer_encoding(x.headers)) { - ret = read_content_chunked(strm, x, out); - } else if (!has_header(x.headers, "Content-Length")) { - ret = read_content_without_length(strm, out); - } else { - auto len = get_header_value_u64(x.headers, "Content-Length", 0, 0); - if (len > payload_max_length) { + auto result = read_content_chunked(strm, x, payload_max_length, out); + if (result == ReadContentResult::Success) { + ret = true; + } else if (result == ReadContentResult::PayloadTooLarge) { 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); + } else { + ret = false; } - } + } else if (!has_header(x.headers, "Content-Length")) { + auto result = + read_content_without_length(strm, payload_max_length, out); + if (result == ReadContentResult::Success) { + ret = true; + } else if (result == ReadContentResult::PayloadTooLarge) { + exceed_payload_max_length = true; + ret = false; + } else { + ret = false; + } + } else { + auto is_invalid_value = false; + auto len = get_header_value_u64(x.headers, "Content-Length", + (std::numeric_limits::max)(), + 0, is_invalid_value); + + if (is_invalid_value) { + ret = false; + } else 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 ? StatusCode::PayloadTooLarge_413 @@ -4033,13 +5105,36 @@ bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status, } return ret; }); -} // namespace detail +} + +inline ssize_t write_request_line(Stream &strm, const std::string &method, + const std::string &path) { + std::string s = method; + s += " "; + s += path; + s += " HTTP/1.1\r\n"; + return strm.write(s.data(), s.size()); +} + +inline ssize_t write_response_line(Stream &strm, int status) { + std::string s = "HTTP/1.1 "; + s += std::to_string(status); + s += " "; + s += CPPHTTPLIB_NAMESPACE::status_message(status); + s += "\r\n"; + return strm.write(s.data(), s.size()); +} 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()); + std::string s; + s = x.first; + s += ": "; + s += x.second; + s += "\r\n"; + + auto len = strm.write(s.data(), s.size()); if (len < 0) { return len; } write_len += len; } @@ -4060,17 +5155,29 @@ inline bool write_data(Stream &strm, const char *d, size_t l) { } template -inline bool write_content(Stream &strm, const ContentProvider &content_provider, - size_t offset, size_t length, T is_shutting_down, - Error &error) { +inline bool write_content_with_progress(Stream &strm, + const ContentProvider &content_provider, + size_t offset, size_t length, + T is_shutting_down, + const UploadProgress &upload_progress, + Error &error) { size_t end_offset = offset + length; + size_t start_offset = offset; auto ok = true; DataSink data_sink; data_sink.write = [&](const char *d, size_t l) -> bool { if (ok) { - if (strm.is_writable() && write_data(strm, d, l)) { + if (write_data(strm, d, l)) { offset += l; + + if (upload_progress && length > 0) { + size_t current_written = offset - start_offset; + if (!upload_progress(current_written, length)) { + ok = false; + return false; + } + } } else { ok = false; } @@ -4078,10 +5185,10 @@ inline bool write_content(Stream &strm, const ContentProvider &content_provider, return ok; }; - data_sink.is_writable = [&]() -> bool { return strm.is_writable(); }; + data_sink.is_writable = [&]() -> bool { return strm.wait_writable(); }; while (offset < end_offset && !is_shutting_down()) { - if (!strm.is_writable()) { + if (!strm.wait_writable()) { error = Error::Write; return false; } else if (!content_provider(offset, end_offset - offset, data_sink)) { @@ -4097,6 +5204,14 @@ inline bool write_content(Stream &strm, const ContentProvider &content_provider, return true; } +template +inline bool write_content(Stream &strm, const ContentProvider &content_provider, + size_t offset, size_t length, T is_shutting_down, + Error &error) { + return write_content_with_progress(strm, content_provider, offset, length, + is_shutting_down, nullptr, error); +} + template inline bool write_content(Stream &strm, const ContentProvider &content_provider, size_t offset, size_t length, @@ -4119,17 +5234,17 @@ write_content_without_length(Stream &strm, data_sink.write = [&](const char *d, size_t l) -> bool { if (ok) { offset += l; - if (!strm.is_writable() || !write_data(strm, d, l)) { ok = false; } + if (!write_data(strm, d, l)) { ok = false; } } return ok; }; - data_sink.is_writable = [&]() -> bool { return strm.is_writable(); }; + data_sink.is_writable = [&]() -> bool { return strm.wait_writable(); }; data_sink.done = [&](void) { data_available = false; }; while (data_available && !is_shutting_down()) { - if (!strm.is_writable()) { + if (!strm.wait_writable()) { return false; } else if (!content_provider(offset, 0, data_sink)) { return false; @@ -4164,10 +5279,7 @@ write_content_chunked(Stream &strm, const ContentProvider &content_provider, // Emit chunked response header and footer for each chunk auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n"; - if (!strm.is_writable() || - !write_data(strm, chunk.data(), chunk.size())) { - ok = false; - } + if (!write_data(strm, chunk.data(), chunk.size())) { ok = false; } } } else { ok = false; @@ -4176,7 +5288,7 @@ write_content_chunked(Stream &strm, const ContentProvider &content_provider, return ok; }; - data_sink.is_writable = [&]() -> bool { return strm.is_writable(); }; + data_sink.is_writable = [&]() -> bool { return strm.wait_writable(); }; auto done_with_trailer = [&](const Headers *trailer) { if (!ok) { return; } @@ -4196,17 +5308,14 @@ write_content_chunked(Stream &strm, const ContentProvider &content_provider, 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 (!strm.is_writable() || - !write_data(strm, chunk.data(), chunk.size())) { + if (!write_data(strm, chunk.data(), chunk.size())) { ok = false; return; } } - const std::string done_marker("0\r\n"); - if (!write_data(strm, done_marker.data(), done_marker.size())) { - ok = false; - } + constexpr const char done_marker[] = "0\r\n"; + if (!write_data(strm, done_marker, str_len(done_marker))) { ok = false; } // Trailer if (trailer) { @@ -4218,8 +5327,8 @@ write_content_chunked(Stream &strm, const ContentProvider &content_provider, } } - const std::string crlf("\r\n"); - if (!write_data(strm, crlf.data(), crlf.size())) { ok = false; } + constexpr const char crlf[] = "\r\n"; + if (!write_data(strm, crlf, str_len(crlf))) { ok = false; } }; data_sink.done = [&](void) { done_with_trailer(nullptr); }; @@ -4229,7 +5338,7 @@ write_content_chunked(Stream &strm, const ContentProvider &content_provider, }; while (data_available && !is_shutting_down()) { - if (!strm.is_writable()) { + if (!strm.wait_writable()) { error = Error::Write; return false; } else if (!content_provider(offset, 0, data_sink)) { @@ -4286,36 +5395,40 @@ inline std::string params_to_query_str(const Params ¶ms) { for (auto it = params.begin(); it != params.end(); ++it) { if (it != params.begin()) { query += "&"; } - query += it->first; + query += encode_query_component(it->first); query += "="; - query += encode_query_param(it->second); + query += encode_query_component(it->second); } return query; } -inline void parse_query_text(const std::string &s, Params ¶ms) { +inline void parse_query_text(const char *data, std::size_t size, + Params ¶ms) { std::set cache; - split(s.data(), s.data() + s.size(), '&', [&](const char *b, const char *e) { + split(data, data + size, '&', [&](const char *b, const char *e) { std::string kv(b, e); if (cache.find(kv) != cache.end()) { return; } - cache.insert(kv); + cache.insert(std::move(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); - } - }); + divide(b, static_cast(e - b), '=', + [&](const char *lhs_data, std::size_t lhs_size, const char *rhs_data, + std::size_t rhs_size) { + key.assign(lhs_data, lhs_size); + val.assign(rhs_data, rhs_size); + }); if (!key.empty()) { - params.emplace(decode_url(key, true), decode_url(val, true)); + params.emplace(decode_query_component(key), decode_query_component(val)); } }); } +inline void parse_query_text(const std::string &s, Params ¶ms) { + parse_query_text(s.data(), s.size(), params); +} + inline bool parse_multipart_boundary(const std::string &content_type, std::string &boundary) { auto boundary_keyword = "boundary="; @@ -4356,35 +5469,44 @@ 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 - auto re_first_range = Regex(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))"); - Match m; - if (RegexMatch(s, m, re_first_range)) { - auto pos = static_cast(m.position(1)); - auto len = static_cast(m.length(1)); + auto is_valid = [](const std::string &str) { + return std::all_of(str.cbegin(), str.cend(), + [](unsigned char c) { return std::isdigit(c); }); + }; + + if (s.size() > 7 && s.compare(0, 6, "bytes=") == 0) { + const auto pos = static_cast(6); + const auto len = static_cast(s.size() - 6); auto all_valid_ranges = true; split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) { if (!all_valid_ranges) { return; } - auto re_another_range = Regex(R"(\s*(\d*)-(\d*))"); - Match cm; - if (RegexMatch(b, e, cm, re_another_range)) { - ssize_t first = -1; - if (!cm.str(1).empty()) { - first = static_cast(std::stoll(cm.str(1))); - } - ssize_t last = -1; - if (!cm.str(2).empty()) { - last = static_cast(std::stoll(cm.str(2))); - } + const auto it = std::find(b, e, '-'); + if (it == e) { + all_valid_ranges = false; + return; + } - if (first != -1 && last != -1 && first > last) { - all_valid_ranges = false; - return; - } - ranges.emplace_back(std::make_pair(first, last)); + const auto lhs = std::string(b, it); + const auto rhs = std::string(it + 1, e); + if (!is_valid(lhs) || !is_valid(rhs)) { + all_valid_ranges = false; + return; } + + const auto first = + static_cast(lhs.empty() ? -1 : std::stoll(lhs)); + const auto last = + static_cast(rhs.empty() ? -1 : std::stoll(rhs)); + if ((first == -1 && last == -1) || + (first != -1 && last != -1 && first > last)) { + all_valid_ranges = false; + return; + } + + ranges.emplace_back(first, last); }); - return all_valid_ranges; + return all_valid_ranges && !ranges.empty(); } return false; #ifdef CPPHTTPLIB_NO_EXCEPTIONS @@ -4393,9 +5515,139 @@ inline bool parse_range_header(const std::string &s, Ranges &ranges) try { } catch (...) { return false; } #endif -class MultipartFormDataParser { +inline bool parse_accept_header(const std::string &s, + std::vector &content_types) { + content_types.clear(); + + // Empty string is considered valid (no preference) + if (s.empty()) { return true; } + + // Check for invalid patterns: leading/trailing commas or consecutive commas + if (s.front() == ',' || s.back() == ',' || + s.find(",,") != std::string::npos) { + return false; + } + + struct AcceptEntry { + std::string media_type; + double quality; + int order; // Original order in header + }; + + std::vector entries; + int order = 0; + bool has_invalid_entry = false; + + // Split by comma and parse each entry + split(s.data(), s.data() + s.size(), ',', [&](const char *b, const char *e) { + std::string entry(b, e); + entry = trim_copy(entry); + + if (entry.empty()) { + has_invalid_entry = true; + return; + } + + AcceptEntry accept_entry; + accept_entry.quality = 1.0; // Default quality + accept_entry.order = order++; + + // Find q= parameter + auto q_pos = entry.find(";q="); + if (q_pos == std::string::npos) { q_pos = entry.find("; q="); } + + if (q_pos != std::string::npos) { + // Extract media type (before q parameter) + accept_entry.media_type = trim_copy(entry.substr(0, q_pos)); + + // Extract quality value + auto q_start = entry.find('=', q_pos) + 1; + auto q_end = entry.find(';', q_start); + if (q_end == std::string::npos) { q_end = entry.length(); } + + std::string quality_str = + trim_copy(entry.substr(q_start, q_end - q_start)); + if (quality_str.empty()) { + has_invalid_entry = true; + return; + } + +#ifdef CPPHTTPLIB_NO_EXCEPTIONS + { + std::istringstream iss(quality_str); + iss >> accept_entry.quality; + + // Check if conversion was successful and entire string was consumed + if (iss.fail() || !iss.eof()) { + has_invalid_entry = true; + return; + } + } +#else + try { + accept_entry.quality = std::stod(quality_str); + } catch (...) { + has_invalid_entry = true; + return; + } +#endif + // Check if quality is in valid range [0.0, 1.0] + if (accept_entry.quality < 0.0 || accept_entry.quality > 1.0) { + has_invalid_entry = true; + return; + } + } else { + // No quality parameter, use entire entry as media type + accept_entry.media_type = entry; + } + + // Remove additional parameters from media type + auto param_pos = accept_entry.media_type.find(';'); + if (param_pos != std::string::npos) { + accept_entry.media_type = + trim_copy(accept_entry.media_type.substr(0, param_pos)); + } + + // Basic validation of media type format + if (accept_entry.media_type.empty()) { + has_invalid_entry = true; + return; + } + + // Check for basic media type format (should contain '/' or be '*') + if (accept_entry.media_type != "*" && + accept_entry.media_type.find('/') == std::string::npos) { + has_invalid_entry = true; + return; + } + + entries.push_back(accept_entry); + }); + + // Return false if any invalid entry was found + if (has_invalid_entry) { return false; } + + // Sort by quality (descending), then by original order (ascending) + std::sort(entries.begin(), entries.end(), + [](const AcceptEntry &a, const AcceptEntry &b) { + if (a.quality != b.quality) { + return a.quality > b.quality; // Higher quality first + } + return a.order < b.order; // Earlier order first for same quality + }); + + // Extract sorted media types + content_types.reserve(entries.size()); + for (const auto &entry : entries) { + content_types.push_back(entry.media_type); + } + + return true; +} + +class FormDataParser { public: - MultipartFormDataParser() = default; + FormDataParser() = default; void set_boundary(std::string &&boundary) { boundary_ = boundary; @@ -4405,18 +5657,17 @@ class MultipartFormDataParser { bool is_valid() const { return is_valid_; } - bool parse(const char *buf, size_t n, const ContentReceiver &content_callback, - const MultipartContentHeader &header_callback) { + bool parse(const char *buf, size_t n, const FormDataHeader &header_callback, + const ContentReceiver &content_callback) { buf_append(buf, n); while (buf_size() > 0) { switch (state_) { case 0: { // Initial boundary - buf_erase(buf_find(dash_boundary_crlf_)); - if (dash_boundary_crlf_.size() > buf_size()) { return true; } - if (!buf_start_with(dash_boundary_crlf_)) { return false; } - buf_erase(dash_boundary_crlf_.size()); + auto pos = buf_find(dash_boundary_crlf_); + if (pos == buf_size()) { return true; } + buf_erase(pos + dash_boundary_crlf_.size()); state_ = 1; break; } @@ -4443,18 +5694,28 @@ class MultipartFormDataParser { const auto header = buf_head(pos); if (!parse_header(header.data(), header.data() + header.size(), - [&](std::string &&, std::string &&) {})) { + [&](const std::string &, const std::string &) {})) { is_valid_ = false; return false; } - const std::string header_content_type = "Content-Type:"; + // Parse and emplace space trimmed headers into a map + if (!parse_header( + header.data(), header.data() + header.size(), + [&](const std::string &key, const std::string &val) { + file_.headers.emplace(key, val); + })) { + is_valid_ = false; + return false; + } + + constexpr const char header_content_type[] = "Content-Type:"; if (start_with_case_ignore(header, header_content_type)) { file_.content_type = - trim_copy(header.substr(header_content_type.size())); + trim_copy(header.substr(str_len(header_content_type))); } else { - const Regex re_content_disposition( + thread_local const Regex re_content_disposition( R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~", duckdb_re2::RegexOptions::CASE_INSENSITIVE); @@ -4476,13 +5737,13 @@ class MultipartFormDataParser { it = params.find("filename*"); if (it != params.end()) { - // Only allow UTF-8 enconnding... - const Regex re_rfc5987_encoding( + // Only allow UTF-8 encoding... + thread_local const Regex re_rfc5987_encoding( R"~(^UTF-8''(.+?)$)~", duckdb_re2::RegexOptions::CASE_INSENSITIVE); Match m2; if (RegexMatch(it->second, m2, re_rfc5987_encoding)) { - file_.filename = decode_url(m2[1], false); // override... + file_.filename = decode_path_component(m2[1]); // override... } else { is_valid_ = false; return false; @@ -4547,13 +5808,16 @@ class MultipartFormDataParser { file_.name.clear(); file_.filename.clear(); file_.content_type.clear(); + file_.headers.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; } + bool start_with_case_ignore(const std::string &a, const char *b) const { + const auto b_len = strlen(b); + if (a.size() < b_len) { return false; } + for (size_t i = 0; i < b_len; i++) { + if (case_ignore::to_lower(a[i]) != case_ignore::to_lower(b[i])) { + return false; + } } return true; } @@ -4566,7 +5830,7 @@ class MultipartFormDataParser { size_t state_ = 0; bool is_valid_ = false; - MultipartFormData file_; + FormData file_; // Buffer bool start_with(const std::string &a, size_t spos, size_t epos, @@ -4636,27 +5900,22 @@ class MultipartFormDataParser { 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(::tolower(*it)); - it++; - } - return out; +// 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(std::rand()) % max_index]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; } inline std::string make_multipart_data_boundary() { - static const char data[] = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - std::string result = "--cpp-httplib-multipart-data-"; - duckdb::RandomEngine engine; - for (auto i = 0; i < 16; i++) { - result += data[engine.NextRandomInteger32(0,sizeof(data) - 1)]; - } - - return result; + return "--cpp-httplib-multipart-data-" + detail::random_string(16); } inline bool is_multipart_boundary_chars_valid(const std::string &boundary) { @@ -4702,7 +5961,7 @@ serialize_multipart_formdata_get_content_type(const std::string &boundary) { } inline std::string -serialize_multipart_formdata(const MultipartFormDataItems &items, +serialize_multipart_formdata(const UploadFormDataItems &items, const std::string &boundary, bool finish = true) { std::string body; @@ -4716,44 +5975,160 @@ serialize_multipart_formdata(const MultipartFormDataItems &items, return body; } -inline std::pair -get_range_offset_and_length(const Request &req, size_t content_length, - size_t index) { - auto r = req.ranges[index]; +inline void coalesce_ranges(Ranges &ranges, size_t content_length) { + if (ranges.size() <= 1) return; + + // Sort ranges by start position + std::sort(ranges.begin(), ranges.end(), + [](const Range &a, const Range &b) { return a.first < b.first; }); + + Ranges coalesced; + coalesced.reserve(ranges.size()); + + for (auto &r : ranges) { + auto first_pos = r.first; + auto last_pos = r.second; + + // Handle special cases like in range_error + if (first_pos == -1 && last_pos == -1) { + first_pos = 0; + last_pos = static_cast(content_length); + } + + if (first_pos == -1) { + first_pos = static_cast(content_length) - last_pos; + last_pos = static_cast(content_length) - 1; + } + + if (last_pos == -1 || last_pos >= static_cast(content_length)) { + last_pos = static_cast(content_length) - 1; + } + + // Skip invalid ranges + if (!(0 <= first_pos && first_pos <= last_pos && + last_pos < static_cast(content_length))) { + continue; + } + + // Coalesce with previous range if overlapping or adjacent (but not + // identical) + if (!coalesced.empty()) { + auto &prev = coalesced.back(); + // Check if current range overlaps or is adjacent to previous range + // but don't coalesce identical ranges (allow duplicates) + if (first_pos <= prev.second + 1 && + !(first_pos == prev.first && last_pos == prev.second)) { + // Extend the previous range + prev.second = (std::max)(prev.second, last_pos); + continue; + } + } - if (r.first == -1 && r.second == -1) { - return std::make_pair(0, content_length); + // Add new range + coalesced.emplace_back(first_pos, last_pos); } - auto slen = static_cast(content_length); + ranges = std::move(coalesced); +} + +inline bool range_error(Request &req, Response &res) { + if (!req.ranges.empty() && 200 <= res.status && res.status < 300) { + ssize_t content_len = static_cast( + res.content_length_ ? res.content_length_ : res.body.size()); + + std::vector> processed_ranges; + size_t overwrapping_count = 0; + + // NOTE: The following Range check is based on '14.2. Range' in RFC 9110 + // 'HTTP Semantics' to avoid potential denial-of-service attacks. + // https://www.rfc-editor.org/rfc/rfc9110#section-14.2 + + // Too many ranges + if (req.ranges.size() > CPPHTTPLIB_RANGE_MAX_COUNT) { return true; } + + for (auto &r : req.ranges) { + auto &first_pos = r.first; + auto &last_pos = r.second; + + if (first_pos == -1 && last_pos == -1) { + first_pos = 0; + last_pos = content_len; + } + + if (first_pos == -1) { + first_pos = content_len - last_pos; + last_pos = content_len - 1; + } + + // NOTE: RFC-9110 '14.1.2. Byte Ranges': + // A client can limit the number of bytes requested without knowing the + // size of the selected representation. If the last-pos value is absent, + // or if the value is greater than or equal to the current length of the + // representation data, the byte range is interpreted as the remainder of + // the representation (i.e., the server replaces the value of last-pos + // with a value that is one less than the current length of the selected + // representation). + // https://www.rfc-editor.org/rfc/rfc9110.html#section-14.1.2-6 + if (last_pos == -1 || last_pos >= content_len) { + last_pos = content_len - 1; + } + + // Range must be within content length + if (!(0 <= first_pos && first_pos <= last_pos && + last_pos <= content_len - 1)) { + return true; + } + + // Request must not have more than two overlapping ranges + for (const auto &processed_range : processed_ranges) { + if (!(last_pos < processed_range.first || + first_pos > processed_range.second)) { + overwrapping_count++; + if (overwrapping_count > 2) { return true; } + break; // Only count once per range + } + } + + processed_ranges.emplace_back(first_pos, last_pos); + } - if (r.first == -1) { - r.first = (std::max)(static_cast(0), slen - r.second); - r.second = slen - 1; + // After validation, coalesce overlapping ranges as per RFC 9110 + coalesce_ranges(req.ranges, static_cast(content_len)); } - if (r.second == -1) { r.second = slen - 1; } + return false; +} + +inline std::pair +get_range_offset_and_length(Range r, size_t content_length) { + assert(r.first != -1 && r.second != -1); + assert(0 <= r.first && r.first < static_cast(content_length)); + assert(r.first <= r.second && + r.second < static_cast(content_length)); + (void)(content_length); return std::make_pair(r.first, static_cast(r.second - r.first) + 1); } -inline std::string -make_content_range_header_field(const std::pair &range, - size_t content_length) { +inline std::string make_content_range_header_field( + const std::pair &offset_and_length, size_t content_length) { + auto st = offset_and_length.first; + auto ed = st + offset_and_length.second - 1; + std::string field = "bytes "; - if (range.first != -1) { field += std::to_string(range.first); } + field += std::to_string(st); field += "-"; - if (range.second != -1) { field += std::to_string(range.second); } + field += std::to_string(ed); field += "/"; field += std::to_string(content_length); return field; } template -bool process_multipart_ranges_data(const Request &req, Response &res, +bool process_multipart_ranges_data(const Request &req, const std::string &boundary, const std::string &content_type, - SToken stoken, CToken ctoken, - Content content) { + size_t content_length, SToken stoken, + CToken ctoken, Content content) { for (size_t i = 0; i < req.ranges.size(); i++) { ctoken("--"); stoken(boundary); @@ -4764,16 +6139,17 @@ bool process_multipart_ranges_data(const Request &req, Response &res, ctoken("\r\n"); } + auto offset_and_length = + get_range_offset_and_length(req.ranges[i], content_length); + ctoken("Content-Range: "); - const auto &range = req.ranges[i]; - stoken(make_content_range_header_field(range, res.content_length_)); + stoken(make_content_range_header_field(offset_and_length, content_length)); ctoken("\r\n"); ctoken("\r\n"); - auto offsets = get_range_offset_and_length(req, res.content_length_, i); - auto offset = offsets.first; - auto length = offsets.second; - if (!content(offset, length)) { return false; } + if (!content(offset_and_length.first, offset_and_length.second)) { + return false; + } ctoken("\r\n"); } @@ -4784,31 +6160,30 @@ bool process_multipart_ranges_data(const Request &req, Response &res, return true; } -inline bool make_multipart_ranges_data(const Request &req, Response &res, +inline void make_multipart_ranges_data(const Request &req, Response &res, const std::string &boundary, const std::string &content_type, + size_t content_length, std::string &data) { - return process_multipart_ranges_data( - req, res, boundary, content_type, + process_multipart_ranges_data( + req, boundary, content_type, content_length, [&](const std::string &token) { data += token; }, [&](const std::string &token) { data += token; }, [&](size_t offset, size_t length) { - if (offset < res.body.size()) { - data += res.body.substr(offset, length); - return true; - } - return false; + assert(offset + length <= content_length); + data += res.body.substr(offset, length); + return true; }); } -inline size_t -get_multipart_ranges_data_length(const Request &req, Response &res, - const std::string &boundary, - const std::string &content_type) { +inline size_t get_multipart_ranges_data_length(const Request &req, + const std::string &boundary, + const std::string &content_type, + size_t content_length) { size_t data_length = 0; process_multipart_ranges_data( - req, res, boundary, content_type, + req, boundary, content_type, content_length, [&](const std::string &token) { data_length += token.size(); }, [&](const std::string &token) { data_length += token.size(); }, [&](size_t /*offset*/, size_t length) { @@ -4820,13 +6195,13 @@ get_multipart_ranges_data_length(const Request &req, Response &res, } template -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) { +inline bool +write_multipart_ranges_data(Stream &strm, const Request &req, Response &res, + const std::string &boundary, + const std::string &content_type, + size_t content_length, const T &is_shutting_down) { return process_multipart_ranges_data( - req, res, boundary, content_type, + req, boundary, content_type, content_length, [&](const std::string &token) { strm.write(token); }, [&](const std::string &token) { strm.write(token); }, [&](size_t offset, size_t length) { @@ -4835,24 +6210,16 @@ inline bool write_multipart_ranges_data(Stream &strm, const Request &req, }); } -inline std::pair -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(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") { + req.method == "DELETE") { + return true; + } + if (req.has_header("Content-Length") && + req.get_header_value_u64("Content-Length") > 0) { return true; } - // TODO: check if Content-Length is set + if (is_chunked_transfer_encoding(req.headers)) { return true; } return false; } @@ -4897,41 +6264,107 @@ inline std::string SHA_256(const std::string &s) { inline std::string SHA_512(const std::string &s) { return message_digest(s, EVP_sha512()); } -#endif -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -#ifdef _WIN32 -// 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; } - - auto result = false; - PCCERT_CONTEXT pContext = NULL; - while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) != - nullptr) { - auto encoded_cert = - static_cast(pContext->pbCertEncoded); +inline std::pair make_digest_authentication_header( + const Request &req, const std::map &auth, + size_t cnonce_count, const std::string &cnonce, const std::string &username, + const std::string &password, bool is_proxy = false) { + std::string nc; + { + duckdb::stringstream ss; + ss << std::setfill('0') << std::setw(8) << std::hex << cnonce_count; + nc = ss.str(); + } - auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); - if (x509) { - X509_STORE_add_cert(store, x509); - X509_free(x509); - result = true; + 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(); } } - CertFreeCertificateContext(pContext); - CertCloseStore(hStore, 0); - - return result; -} -#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__) -#if TARGET_OS_OSX -template -using CFObjectPtr = - duckdb::unique_ptr::type, void (*)(CFTypeRef)>; + 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); +} + +inline bool is_ssl_peer_could_be_closed(SSL *ssl, socket_t sock) { + detail::set_nonblocking(sock, true); + auto se = detail::scope_exit([&]() { detail::set_nonblocking(sock, false); }); + + char buf[1]; + return !SSL_peek(ssl, buf, 1) && + SSL_get_error(ssl, 0) == SSL_ERROR_ZERO_RETURN; +} + +#ifdef _WIN32 +// 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; } + + auto result = false; + PCCERT_CONTEXT pContext = NULL; + while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) != + nullptr) { + auto encoded_cert = + static_cast(pContext->pbCertEncoded); + + auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); + if (x509) { + X509_STORE_add_cert(store, x509); + X509_free(x509); + result = true; + } + } + + CertFreeCertificateContext(pContext); + CertCloseStore(hStore, 0); + + return result; +} +#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && TARGET_OS_MAC +template +using CFObjectPtr = + duckdb::unique_ptr::type, void (*)(CFTypeRef)>; inline void cf_object_ptr_deleter(CFTypeRef obj) { if (obj) { CFRelease(obj); } @@ -5016,7 +6449,6 @@ inline bool load_system_certs_on_macos(X509_STORE *store) { return result; } -#endif // TARGET_OS_OSX #endif // _WIN32 #endif // CPPHTTPLIB_OPENSSL_SUPPORT @@ -5038,74 +6470,13 @@ class WSInit { static WSInit wsinit_; #endif -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -inline std::pair make_digest_authentication_header( - const Request &req, const std::map &auth, - size_t cnonce_count, const std::string &cnonce, const std::string &username, - const std::string &password, bool is_proxy = false) { - std::string nc; - { - duckdb::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 &auth, bool is_proxy) { auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate"; if (res.has_header(auth_key)) { - auto re = Regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~"); + thread_local auto re = + Regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~"); auto s = res.get_header_value(auth_key); auto pos = s.find(' '); if (pos != std::string::npos) { @@ -5114,8 +6485,8 @@ inline bool parse_www_authenticate(const Response &res, return false; } else if (type == "Digest") { s = s.substr(pos + 1); - auto matches = duckdb_re2::RegexFindAll(s, re); - for (auto &m : matches) { + auto matches = duckdb_re2::RegexFindAll(s, re); + for (auto &m : matches) { auto key = s.substr(static_cast(m.position(1)), static_cast(m.length(1))); auto val = m.length(2) > 0 @@ -5132,20 +6503,6 @@ inline bool parse_www_authenticate(const Response &res, 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(std::rand()) % max_index]; - }; - std::string str(length, 0); - std::generate_n(str.begin(), length, randchar); - return str; -} - class ContentProviderAdapter { public: explicit ContentProviderAdapter( @@ -5179,12 +6536,14 @@ inline void hosted_at(const std::string &hostname, hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; - if (getaddrinfo(hostname.c_str(), nullptr, &hints, &result)) { + if (detail::getaddrinfo_with_timeout(hostname.c_str(), nullptr, &hints, + &result, 0)) { #if defined __linux__ && !defined __ANDROID__ res_init(); #endif return; } + auto se = detail::scope_exit([&] { freeaddrinfo(result); }); for (auto rp = result; rp; rp = rp->ai_next) { const auto &addr = @@ -5196,24 +6555,256 @@ inline void hosted_at(const std::string &hostname, addrs.push_back(ip); } } +} + +inline std::string encode_uri_component(const std::string &value) { + std::ostringstream escaped; + escaped.fill('0'); + escaped << std::hex; + + for (auto c : value) { + if (std::isalnum(static_cast(c)) || c == '-' || c == '_' || + c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' || + c == ')') { + escaped << c; + } else { + escaped << std::uppercase; + escaped << '%' << std::setw(2) + << static_cast(static_cast(c)); + escaped << std::nouppercase; + } + } + + return escaped.str(); +} + +inline std::string encode_uri(const std::string &value) { + std::ostringstream escaped; + escaped.fill('0'); + escaped << std::hex; + + for (auto c : value) { + if (std::isalnum(static_cast(c)) || c == '-' || c == '_' || + c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' || + c == ')' || c == ';' || c == '/' || c == '?' || c == ':' || c == '@' || + c == '&' || c == '=' || c == '+' || c == '$' || c == ',' || c == '#') { + escaped << c; + } else { + escaped << std::uppercase; + escaped << '%' << std::setw(2) + << static_cast(static_cast(c)); + escaped << std::nouppercase; + } + } + + return escaped.str(); +} + +inline std::string decode_uri_component(const std::string &value) { + std::string result; + + for (size_t i = 0; i < value.size(); i++) { + if (value[i] == '%' && i + 2 < value.size()) { + auto val = 0; + if (detail::from_hex_to_i(value, i + 1, 2, val)) { + result += static_cast(val); + i += 2; + } else { + result += value[i]; + } + } else { + result += value[i]; + } + } + + return result; +} + +inline std::string decode_uri(const std::string &value) { + std::string result; + + for (size_t i = 0; i < value.size(); i++) { + if (value[i] == '%' && i + 2 < value.size()) { + auto val = 0; + if (detail::from_hex_to_i(value, i + 1, 2, val)) { + result += static_cast(val); + i += 2; + } else { + result += value[i]; + } + } else { + result += value[i]; + } + } + + return result; +} + +inline std::string encode_path_component(const std::string &component) { + std::string result; + result.reserve(component.size() * 3); + + for (size_t i = 0; i < component.size(); i++) { + auto c = static_cast(component[i]); + + // Unreserved characters per RFC 3986: ALPHA / DIGIT / "-" / "." / "_" / "~" + if (std::isalnum(c) || c == '-' || c == '.' || c == '_' || c == '~') { + result += static_cast(c); + } + // Path-safe sub-delimiters: "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / + // "," / ";" / "=" + else if (c == '!' || c == '$' || c == '&' || c == '\'' || c == '(' || + c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || + c == '=') { + result += static_cast(c); + } + // Colon is allowed in path segments except first segment + else if (c == ':') { + result += static_cast(c); + } + // @ is allowed in path + else if (c == '@') { + result += static_cast(c); + } else { + result += '%'; + char hex[3]; + snprintf(hex, sizeof(hex), "%02X", c); + result.append(hex, 2); + } + } + return result; +} + +inline std::string decode_path_component(const std::string &component) { + std::string result; + result.reserve(component.size()); + + for (size_t i = 0; i < component.size(); i++) { + if (component[i] == '%' && i + 1 < component.size()) { + if (component[i + 1] == 'u') { + // Unicode %uXXXX encoding + auto val = 0; + if (detail::from_hex_to_i(component, i + 2, 4, val)) { + // 4 digits Unicode codes + char buff[4]; + size_t len = detail::to_utf8(val, buff); + if (len > 0) { result.append(buff, len); } + i += 5; // 'u0000' + } else { + result += component[i]; + } + } else { + // Standard %XX encoding + auto val = 0; + if (detail::from_hex_to_i(component, i + 1, 2, val)) { + // 2 digits hex codes + result += static_cast(val); + i += 2; // 'XX' + } else { + result += component[i]; + } + } + } else { + result += component[i]; + } + } + return result; +} + +inline std::string encode_query_component(const std::string &component, + bool space_as_plus) { + std::string result; + result.reserve(component.size() * 3); + + for (size_t i = 0; i < component.size(); i++) { + auto c = static_cast(component[i]); + + // Unreserved characters per RFC 3986 + if (std::isalnum(c) || c == '-' || c == '.' || c == '_' || c == '~') { + result += static_cast(c); + } + // Space handling + else if (c == ' ') { + if (space_as_plus) { + result += '+'; + } else { + result += "%20"; + } + } + // Plus sign handling + else if (c == '+') { + if (space_as_plus) { + result += "%2B"; + } else { + result += static_cast(c); + } + } + // Query-safe sub-delimiters (excluding & and = which are query delimiters) + else if (c == '!' || c == '$' || c == '\'' || c == '(' || c == ')' || + c == '*' || c == ',' || c == ';') { + result += static_cast(c); + } + // Colon and @ are allowed in query + else if (c == ':' || c == '@') { + result += static_cast(c); + } + // Forward slash is allowed in query values + else if (c == '/') { + result += static_cast(c); + } + // Question mark is allowed in query values (after first ?) + else if (c == '?') { + result += static_cast(c); + } else { + result += '%'; + char hex[3]; + snprintf(hex, sizeof(hex), "%02X", c); + result.append(hex, 2); + } + } + return result; +} - freeaddrinfo(result); +inline std::string decode_query_component(const std::string &component, + bool plus_as_space) { + std::string result; + result.reserve(component.size()); + + for (size_t i = 0; i < component.size(); i++) { + if (component[i] == '%' && i + 2 < component.size()) { + std::string hex = component.substr(i + 1, 2); + char *end; + unsigned long value = std::strtoul(hex.c_str(), &end, 16); + if (end == hex.c_str() + 2) { + result += static_cast(value); + i += 2; + } else { + result += component[i]; + } + } else if (component[i] == '+' && plus_as_space) { + result += ' '; // + becomes space in form-urlencoded + } else { + result += component[i]; + } + } + return result; } inline std::string append_query_params(const std::string &path, const Params ¶ms) { std::string path_with_query = path; - const Regex re("[^?]+\\?.*"); + thread_local const Regex re("[^?]+\\?.*"); auto delm = RegexMatch(path, re) ? '&' : '?'; path_with_query += delm + detail::params_to_query_str(params); return path_with_query; } // Header utilities -inline std::pair make_range_header(Ranges ranges) { +inline std::pair +make_range_header(const Ranges &ranges) { std::string field = "bytes="; auto i = 0; - for (auto r : ranges) { + for (const auto &r : ranges) { if (i != 0) { field += ", "; } if (r.first != -1) { field += std::to_string(r.first); } field += '-'; @@ -5245,8 +6836,8 @@ inline bool Request::has_header(const std::string &key) const { } inline std::string Request::get_header_value(const std::string &key, - size_t id) const { - return detail::get_header_value(headers, key, id, ""); + const char *def, size_t id) const { + return detail::get_header_value(headers, key, def, id); } inline size_t Request::get_header_value_count(const std::string &key) const { @@ -5256,11 +6847,30 @@ inline size_t Request::get_header_value_count(const std::string &key) const { inline void Request::set_header(const std::string &key, const std::string &val) { - if (!detail::has_crlf(key) && !detail::has_crlf(val)) { + if (detail::fields::is_field_name(key) && + detail::fields::is_field_value(val)) { headers.emplace(key, val); } } +inline bool Request::has_trailer(const std::string &key) const { + return trailers.find(key) != trailers.end(); +} + +inline std::string Request::get_trailer_value(const std::string &key, + size_t id) const { + auto rng = trailers.equal_range(key); + auto it = rng.first; + std::advance(it, static_cast(id)); + if (it != rng.second) { return it->second; } + return std::string(); +} + +inline size_t Request::get_trailer_value_count(const std::string &key) const { + auto r = trailers.equal_range(key); + return static_cast(std::distance(r.first, r.second)); +} + inline bool Request::has_param(const std::string &key) const { return params.find(key) != params.end(); } @@ -5284,19 +6894,47 @@ inline bool Request::is_multipart_form_data() const { return !content_type.rfind("multipart/form-data", 0); } -inline bool Request::has_file(const std::string &key) const { - return files.find(key) != files.end(); +// Multipart FormData implementation +inline std::string MultipartFormData::get_field(const std::string &key, + size_t id) const { + auto rng = fields.equal_range(key); + auto it = rng.first; + std::advance(it, static_cast(id)); + if (it != rng.second) { return it->second.content; } + return std::string(); } -inline MultipartFormData Request::get_file_value(const std::string &key) const { - auto it = files.find(key); - if (it != files.end()) { return it->second; } - return MultipartFormData(); +inline std::vector +MultipartFormData::get_fields(const std::string &key) const { + std::vector values; + auto rng = fields.equal_range(key); + for (auto it = rng.first; it != rng.second; it++) { + values.push_back(it->second.content); + } + return values; +} + +inline bool MultipartFormData::has_field(const std::string &key) const { + return fields.find(key) != fields.end(); +} + +inline size_t MultipartFormData::get_field_count(const std::string &key) const { + auto r = fields.equal_range(key); + return static_cast(std::distance(r.first, r.second)); +} + +inline FormData MultipartFormData::get_file(const std::string &key, + size_t id) const { + auto rng = files.equal_range(key); + auto it = rng.first; + std::advance(it, static_cast(id)); + if (it != rng.second) { return it->second; } + return FormData(); } -inline std::vector -Request::get_file_values(const std::string &key) const { - std::vector values; +inline std::vector +MultipartFormData::get_files(const std::string &key) const { + std::vector values; auto rng = files.equal_range(key); for (auto it = rng.first; it != rng.second; it++) { values.push_back(it->second); @@ -5304,14 +6942,24 @@ Request::get_file_values(const std::string &key) const { return values; } +inline bool MultipartFormData::has_file(const std::string &key) const { + return files.find(key) != files.end(); +} + +inline size_t MultipartFormData::get_file_count(const std::string &key) const { + auto r = files.equal_range(key); + return static_cast(std::distance(r.first, r.second)); +} + // Response implementation inline bool Response::has_header(const std::string &key) const { return headers.find(key) != headers.end(); } inline std::string Response::get_header_value(const std::string &key, + const char *def, size_t id) const { - return detail::get_header_value(headers, key, id, ""); + return detail::get_header_value(headers, key, def, id); } inline size_t Response::get_header_value_count(const std::string &key) const { @@ -5321,13 +6969,31 @@ inline size_t Response::get_header_value_count(const std::string &key) const { inline void Response::set_header(const std::string &key, const std::string &val) { - if (!detail::has_crlf(key) && !detail::has_crlf(val)) { + if (detail::fields::is_field_name(key) && + detail::fields::is_field_value(val)) { headers.emplace(key, val); } } +inline bool Response::has_trailer(const std::string &key) const { + return trailers.find(key) != trailers.end(); +} + +inline std::string Response::get_trailer_value(const std::string &key, + size_t id) const { + auto rng = trailers.equal_range(key); + auto it = rng.first; + std::advance(it, static_cast(id)); + if (it != rng.second) { return it->second; } + return std::string(); +} + +inline size_t Response::get_trailer_value_count(const std::string &key) const { + auto r = trailers.equal_range(key); + return static_cast(std::distance(r.first, r.second)); +} inline void Response::set_redirect(const std::string &url, int stat) { - if (!detail::has_crlf(url)) { + if (detail::fields::is_field_value(url)) { set_header("Location", url); if (300 <= stat && stat < 400) { this->status = stat; @@ -5351,13 +7017,22 @@ inline void Response::set_content(const std::string &s, set_content(s.data(), s.size(), content_type); } +inline void Response::set_content(std::string &&s, + const std::string &content_type) { + body = std::move(s); + + auto rng = headers.equal_range("Content-Type"); + headers.erase(rng.first, rng.second); + set_header("Content-Type", content_type); +} + inline void Response::set_content_provider( size_t in_length, const std::string &content_type, ContentProvider provider, ContentProviderResourceReleaser resource_releaser) { set_header("Content-Type", content_type); content_length_ = in_length; if (in_length > 0) { content_provider_ = std::move(provider); } - content_provider_resource_releaser_ = resource_releaser; + content_provider_resource_releaser_ = std::move(resource_releaser); is_chunked_content_provider_ = false; } @@ -5367,7 +7042,7 @@ inline void Response::set_content_provider( set_header("Content-Type", content_type); content_length_ = 0; content_provider_ = detail::ContentProviderAdapter(std::move(provider)); - content_provider_resource_releaser_ = resource_releaser; + content_provider_resource_releaser_ = std::move(resource_releaser); is_chunked_content_provider_ = false; } @@ -5377,18 +7052,29 @@ inline void Response::set_chunked_content_provider( set_header("Content-Type", content_type); content_length_ = 0; content_provider_ = detail::ContentProviderAdapter(std::move(provider)); - content_provider_resource_releaser_ = resource_releaser; + content_provider_resource_releaser_ = std::move(resource_releaser); is_chunked_content_provider_ = true; } +inline void Response::set_file_content(const std::string &path, + const std::string &content_type) { + file_content_path_ = path; + file_content_content_type_ = content_type; +} + +inline void Response::set_file_content(const std::string &path) { + file_content_path_ = path; +} + // Result implementation inline bool Result::has_request_header(const std::string &key) const { return request_headers_.find(key) != request_headers_.end(); } inline std::string Result::get_request_header_value(const std::string &key, + const char *def, size_t id) const { - return detail::get_header_value(request_headers_, key, id, ""); + return detail::get_header_value(request_headers_, key, def, id); } inline size_t @@ -5408,23 +7094,54 @@ inline ssize_t Stream::write(const std::string &s) { namespace detail { +inline void calc_actual_timeout(time_t max_timeout_msec, time_t duration_msec, + time_t timeout_sec, time_t timeout_usec, + time_t &actual_timeout_sec, + time_t &actual_timeout_usec) { + auto timeout_msec = (timeout_sec * 1000) + (timeout_usec / 1000); + + auto actual_timeout_msec = + (std::min)(max_timeout_msec - duration_msec, timeout_msec); + + if (actual_timeout_msec < 0) { actual_timeout_msec = 0; } + + actual_timeout_sec = actual_timeout_msec / 1000; + actual_timeout_usec = (actual_timeout_msec % 1000) * 1000; +} + // 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) +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, + time_t max_timeout_msec, + std::chrono::time_point start_time) : 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) {} + write_timeout_usec_(write_timeout_usec), + max_timeout_msec_(max_timeout_msec), start_time_(start_time), + read_buff_(read_buff_size_, 0) {} inline SocketStream::~SocketStream() = default; inline bool SocketStream::is_readable() const { - return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0; + return read_buff_off_ < read_buff_content_size_; +} + +inline bool SocketStream::wait_readable() const { + if (max_timeout_msec_ <= 0) { + return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0; + } + + time_t read_timeout_sec; + time_t read_timeout_usec; + calc_actual_timeout(max_timeout_msec_, duration(), read_timeout_sec_, + read_timeout_usec_, read_timeout_sec, read_timeout_usec); + + return select_read(sock_, read_timeout_sec, read_timeout_usec) > 0; } -inline bool SocketStream::is_writable() const { +inline bool SocketStream::wait_writable() const { return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 && is_socket_alive(sock_); } @@ -5451,7 +7168,7 @@ inline ssize_t SocketStream::read(char *ptr, size_t size) { } } - if (!is_readable()) { return -1; } + if (!wait_readable()) { return -1; } read_buff_off_ = 0; read_buff_content_size_ = 0; @@ -5476,7 +7193,7 @@ inline ssize_t SocketStream::read(char *ptr, size_t size) { } inline ssize_t SocketStream::write(const char *ptr, size_t size) { - if (!is_writable()) { return -1; } + if (!wait_writable()) { return -1; } #if defined(_WIN32) && !defined(_WIN64) size = @@ -5498,10 +7215,18 @@ inline void SocketStream::get_local_ip_and_port(std::string &ip, inline socket_t SocketStream::socket() const { return sock_; } +inline time_t SocketStream::duration() const { + return std::chrono::duration_cast( + std::chrono::steady_clock::now() - start_time_) + .count(); +} + // Buffer stream implementation inline bool BufferStream::is_readable() const { return true; } -inline bool BufferStream::is_writable() const { return true; } +inline bool BufferStream::wait_readable() const { return true; } + +inline bool BufferStream::wait_writable() const { return true; } inline ssize_t BufferStream::read(char *ptr, size_t size) { #if defined(_MSC_VER) && _MSC_VER < 1910 @@ -5526,9 +7251,14 @@ inline void BufferStream::get_local_ip_and_port(std::string & /*ip*/, inline socket_t BufferStream::socket() const { return 0; } +inline time_t BufferStream::duration() const { return 0; } + inline const std::string &BufferStream::get_buffer() const { return buffer; } -inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) { +inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) + : MatcherBase(pattern) { + constexpr const char marker[] = "/:"; + // One past the last ending position of a path param substring std::size_t last_param_end = 0; @@ -5541,13 +7271,14 @@ inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) { #endif while (true) { - const auto marker_pos = pattern.find(marker, last_param_end); + const auto marker_pos = pattern.find( + marker, last_param_end == 0 ? last_param_end : last_param_end - 1); if (marker_pos == std::string::npos) { break; } static_fragments_.push_back( - pattern.substr(last_param_end, marker_pos - last_param_end)); + pattern.substr(last_param_end, marker_pos - last_param_end + 1)); - const auto param_name_start = marker_pos + 1; + const auto param_name_start = marker_pos + str_len(marker); auto sep_pos = pattern.find(separator, param_name_start); if (sep_pos == std::string::npos) { sep_pos = pattern.length(); } @@ -5609,7 +7340,7 @@ inline bool PathParamsMatcher::match(Request &request) const { request.path_params.emplace( param_name, request.path.substr(starting_pos, sep_pos - starting_pos)); - // Mark everythin up to '/' as matched + // Mark everything up to '/' as matched starting_pos = sep_pos + 1; } // Returns false if the path is longer than the pattern @@ -5621,6 +7352,30 @@ inline bool RegexMatcher::match(Request &request) const { return RegexMatch(request.path, request.matches, regex_); } +inline std::string make_host_and_port_string(const std::string &host, int port, + bool is_ssl) { + std::string result; + + // Enclose IPv6 address in brackets (but not if already enclosed) + if (host.find(':') == std::string::npos || + (!host.empty() && host[0] == '[')) { + // IPv4, hostname, or already bracketed IPv6 + result = host; + } else { + // IPv6 address without brackets + result = "[" + host + "]"; + } + + // Append port if not default + if ((!is_ssl && port == 80) || (is_ssl && port == 443)) { + ; // do nothing + } else { + result += ":" + std::to_string(port); + } + + return result; +} + } // namespace detail // HTTP server implementation @@ -5708,7 +7463,8 @@ inline bool Server::set_base_dir(const std::string &dir, inline bool Server::set_mount_point(const std::string &mount_point, const std::string &dir, Headers headers) { - if (detail::is_dir(dir)) { + detail::FileStat stat(dir); + if (stat.is_dir()) { std::string mnt = !mount_point.empty() ? mount_point : "/"; if (!mnt.empty() && mnt[0] == '/') { base_dirs_.push_back({mnt, dir, std::move(headers)}); @@ -5745,12 +7501,14 @@ inline Server &Server::set_file_request_handler(Handler handler) { return *this; } -inline Server &Server::set_error_handler(HandlerWithResponse handler) { +inline Server &Server::set_error_handler_core(HandlerWithResponse handler, + std::true_type) { error_handler_ = std::move(handler); return *this; } -inline Server &Server::set_error_handler(Handler handler) { +inline Server &Server::set_error_handler_core(Handler handler, + std::false_type) { error_handler_ = [handler](const Request &req, Response &res) { handler(req, res); return HandlerResponse::Handled; @@ -5773,11 +7531,26 @@ inline Server &Server::set_post_routing_handler(Handler handler) { return *this; } +inline Server &Server::set_pre_request_handler(HandlerWithResponse handler) { + pre_request_handler_ = std::move(handler); + return *this; +} + inline Server &Server::set_logger(Logger logger) { logger_ = std::move(logger); return *this; } +inline Server &Server::set_error_logger(ErrorLogger error_logger) { + error_logger_ = std::move(error_logger); + return *this; +} + +inline Server &Server::set_pre_compression_logger(Logger logger) { + pre_compression_logger_ = std::move(logger); + return *this; +} + inline Server & Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) { expect_100_continue_handler_ = std::move(handler); @@ -5794,6 +7567,11 @@ inline Server &Server::set_tcp_nodelay(bool on) { return *this; } +inline Server &Server::set_ipv6_v6only(bool on) { + ipv6_v6only_ = on; + return *this; +} + inline Server &Server::set_socket_options(SocketOptions socket_options) { socket_options_ = std::move(socket_options); return *this; @@ -5810,6 +7588,12 @@ inline Server &Server::set_header_writer( return *this; } +inline Server & +Server::set_trusted_proxies(const std::vector &proxies) { + trusted_proxies_ = proxies; + return *this; +} + inline Server &Server::set_keep_alive_max_count(size_t count) { keep_alive_max_count_ = count; return *this; @@ -5845,27 +7629,27 @@ inline Server &Server::set_payload_max_length(size_t length) { inline bool Server::bind_to_port(const std::string &host, int port, int socket_flags) { - return bind_internal(host, port, socket_flags) >= 0; + auto ret = bind_internal(host, port, socket_flags); + if (ret == -1) { is_decommissioned = true; } + return ret >= 0; } inline int Server::bind_to_any_port(const std::string &host, int socket_flags) { - return bind_internal(host, 0, socket_flags); + auto ret = bind_internal(host, 0, socket_flags); + if (ret == -1) { is_decommissioned = true; } + return ret; } -inline bool Server::listen_after_bind() { - auto se = detail::scope_exit([&]() { done_ = true; }); - return listen_internal(); -} +inline bool Server::listen_after_bind() { return listen_internal(); } inline bool Server::listen(const std::string &host, int port, int socket_flags) { - auto se = detail::scope_exit([&]() { done_ = true; }); return bind_to_port(host, port, socket_flags) && listen_internal(); } inline bool Server::is_running() const { return is_running_; } inline void Server::wait_until_ready() const { - while (!is_running() && !done_) { + while (!is_running_ && !is_decommissioned) { std::this_thread::sleep_for(std::chrono::milliseconds{1}); } } @@ -5877,11 +7661,14 @@ inline void Server::stop() { detail::shutdown_socket(sock); detail::close_socket(sock); } + is_decommissioned = false; } +inline void Server::decommission() { is_decommissioned = true; } + static const std::set SERVER_METHODS{ - "GET", "HEAD", "POST", "PUT", "DELETE", - "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"}; + "GET", "HEAD", "POST", "PUT", "DELETE", + "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"}; inline bool Server::parse_request_line(const char *s, Request &req) const { auto len = strlen(s); @@ -5906,7 +7693,10 @@ inline bool Server::parse_request_line(const char *s, Request &req) const { if (SERVER_METHODS.find(req.method) == SERVER_METHODS.end()) { return false; } - if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; } + if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { + output_error_log(Error::InvalidHTTPVersion, &req); + return false; + } { // Skip URL fragment @@ -5917,33 +7707,23 @@ inline bool Server::parse_request_line(const char *s, Request &req) const { } } - size_t count = 0; - - detail::split(req.target.data(), req.target.data() + req.target.size(), '?', - 2, [&](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; } + detail::divide(req.target, '?', + [&](const char *lhs_data, std::size_t lhs_size, + const char *rhs_data, std::size_t rhs_size) { + req.path = + decode_path_component(std::string(lhs_data, lhs_size)); + detail::parse_query_text(rhs_data, rhs_size, req.params); + }); } return true; } inline bool Server::write_response(Stream &strm, bool close_connection, - const Request &req, Response &res) { + Request &req, Response &res) { + // NOTE: `req.ranges` should be empty, otherwise it will be applied + // incorrectly to the error content. + req.ranges.clear(); return write_response_core(strm, close_connection, req, res, false); } @@ -5972,23 +7752,24 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection, if (close_connection || req.get_header_value("Connection") == "close") { res.set_header("Connection", "close"); } else { - duckdb::stringstream ss; - ss << "timeout=" << keep_alive_timeout_sec_ - << ", max=" << keep_alive_max_count_; - res.set_header("Keep-Alive", ss.str()); + std::string s = "timeout="; + s += std::to_string(keep_alive_timeout_sec_); + s += ", max="; + s += std::to_string(keep_alive_max_count_); + res.set_header("Keep-Alive", s); } - if (!res.has_header("Content-Type") && - (!res.body.empty() || res.content_length_ > 0 || res.content_provider_)) { + if ((!res.body.empty() || res.content_length_ > 0 || res.content_provider_) && + !res.has_header("Content-Type")) { res.set_header("Content-Type", "text/plain"); } - if (!res.has_header("Content-Length") && res.body.empty() && - !res.content_length_ && !res.content_provider_) { + if (res.body.empty() && !res.content_length_ && !res.content_provider_ && + !res.has_header("Content-Length")) { res.set_header("Content-Length", "0"); } - if (!res.has_header("Accept-Ranges") && req.method == "HEAD") { + if (req.method == "HEAD" && !res.has_header("Accept-Ranges")) { res.set_header("Accept-Ranges", "bytes"); } @@ -5997,12 +7778,7 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection, // Response line and headers { detail::BufferStream bstrm; - - if (!bstrm.write_format("HTTP/1.1 %d %s\r\n", res.status, - status_message(res.status))) { - return false; - } - + if (!detail::write_response_line(bstrm, res.status)) { return false; } if (!header_writer_(bstrm, res.headers)) { return false; } // Flush buffer @@ -6021,14 +7797,13 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection, 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); } + output_log(req, res); return ret; } @@ -6046,15 +7821,16 @@ Server::write_content_with_provider(Stream &strm, const Request &req, 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); + auto offset_and_length = detail::get_range_offset_and_length( + req.ranges[0], res.content_length_); + + return detail::write_content(strm, res.content_provider_, + offset_and_length.first, + offset_and_length.second, is_shutting_down); } else { return detail::write_multipart_ranges_data( - strm, req, res, boundary, content_type, is_shutting_down); + strm, req, res, boundary, content_type, res.content_length_, + is_shutting_down); } } else { if (res.is_chunked_content_provider_) { @@ -6068,6 +7844,10 @@ Server::write_content_with_provider(Stream &strm, const Request &req, } else if (type == detail::EncodingType::Brotli) { #ifdef CPPHTTPLIB_BROTLI_SUPPORT compressor = detail::make_unique(); +#endif + } else if (type == detail::EncodingType::Zstd) { +#ifdef CPPHTTPLIB_ZSTD_SUPPORT + compressor = detail::make_unique(); #endif } else { compressor = detail::make_unique(); @@ -6084,34 +7864,53 @@ Server::write_content_with_provider(Stream &strm, const Request &req, } inline bool Server::read_content(Stream &strm, Request &req, Response &res) { - MultipartFormDataMap::iterator cur; - auto file_count = 0; + FormFields::iterator cur_field; + FormFiles::iterator cur_file; + auto is_text_field = false; + size_t count = 0; 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; } + if (req.body.size() + n > payload_max_length_ || + req.body.size() + n > req.body.max_size()) { return false; } req.body.append(buf, n); return true; }, - // Multipart - [&](const MultipartFormData &file) { - if (file_count++ == CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT) { + // Multipart FormData + [&](const FormData &file) { + if (count++ == CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT) { + output_error_log(Error::TooManyFormDataFiles, &req); return false; } - cur = req.files.emplace(file.name, file); + + if (file.filename.empty()) { + cur_field = req.form.fields.emplace( + file.name, FormField{file.name, file.content, file.headers}); + is_text_field = true; + } else { + cur_file = req.form.files.emplace(file.name, file); + is_text_field = false; + } 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); + if (is_text_field) { + auto &content = cur_field->second.content; + if (content.size() + n > content.max_size()) { return false; } + content.append(buf, n); + } else { + auto &content = cur_file->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_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH) { res.status = StatusCode::PayloadTooLarge_413; // NOTE: should be 414? + output_error_log(Error::ExceedMaxPayloadSize, &req); return false; } detail::parse_query_text(req.body, req.params); @@ -6123,19 +7922,16 @@ inline bool Server::read_content(Stream &strm, Request &req, Response &res) { inline bool Server::read_content_with_content_receiver( Stream &strm, Request &req, Response &res, ContentReceiver receiver, - MultipartContentHeader multipart_header, - ContentReceiver multipart_receiver) { + FormDataHeader 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 multipart_header, - ContentReceiver multipart_receiver) const { - detail::MultipartFormDataParser multipart_form_data_parser; +inline bool Server::read_content_core( + Stream &strm, Request &req, Response &res, ContentReceiver receiver, + FormDataHeader multipart_header, ContentReceiver multipart_receiver) const { + detail::FormDataParser multipart_form_data_parser; ContentReceiverWithProgress out; if (req.is_multipart_form_data()) { @@ -6143,28 +7939,18 @@ Server::read_content_core(Stream &strm, Request &req, Response &res, std::string boundary; if (!detail::parse_multipart_boundary(content_type, boundary)) { res.status = StatusCode::BadRequest_400; + output_error_log(Error::MultipartParsing, &req); 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)(1, n - pos); - auto ret = multipart_form_data_parser.parse( - buf + pos, read_size, multipart_receiver, multipart_header); - if (!ret) { return false; } - pos += read_size; - } - return true; - */ - return multipart_form_data_parser.parse(buf, n, multipart_receiver, - multipart_header); + out = [&](const char *buf, size_t n, size_t /*off*/, size_t /*len*/) { + return multipart_form_data_parser.parse(buf, n, multipart_header, + multipart_receiver); }; } else { - out = [receiver](const char *buf, size_t n, uint64_t /*off*/, - uint64_t /*len*/) { return receiver(buf, n); }; + out = [receiver](const char *buf, size_t n, size_t /*off*/, + size_t /*len*/) { return receiver(buf, n); }; } if (req.method == "DELETE" && !req.has_header("Content-Length")) { @@ -6179,6 +7965,7 @@ Server::read_content_core(Stream &strm, Request &req, Response &res, if (req.is_multipart_form_data()) { if (!multipart_form_data_parser.is_valid()) { res.status = StatusCode::BadRequest_400; + output_error_log(Error::MultipartParsing, &req); return false; } } @@ -6186,8 +7973,7 @@ Server::read_content_core(Stream &strm, Request &req, Response &res, return true; } -inline bool Server::handle_file_request(const Request &req, Response &res, - bool head) { +inline bool Server::handle_file_request(const Request &req, Response &res) { for (const auto &entry : base_dirs_) { // Prefix match if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) { @@ -6196,13 +7982,23 @@ inline bool Server::handle_file_request(const Request &req, Response &res, auto path = entry.base_dir + sub_path; if (path.back() == '/') { path += "index.html"; } - if (detail::is_file(path)) { + detail::FileStat stat(path); + + if (stat.is_dir()) { + res.set_redirect(sub_path + "/", StatusCode::MovedPermanently_301); + return true; + } + + if (stat.is_file()) { for (const auto &kv : entry.headers) { res.set_header(kv.first, kv.second); } auto mm = duckdb::make_shared_ptr(path.c_str()); - if (!mm->is_open()) { return false; } + if (!mm->is_open()) { + output_error_log(Error::OpenFile, &req); + return false; + } res.set_content_provider( mm->size(), @@ -6213,11 +8009,13 @@ inline bool Server::handle_file_request(const Request &req, Response &res, return true; }); - if (!head && file_request_handler_) { + if (req.method != "HEAD" && file_request_handler_) { file_request_handler_(req, res); } return true; + } else { + output_error_log(Error::OpenFile, &req); } } } @@ -6231,18 +8029,24 @@ Server::create_server_socket(const std::string &host, int port, SocketOptions socket_options) const { return detail::create_socket( host, std::string(), port, address_family_, socket_flags, tcp_nodelay_, - std::move(socket_options), - [](socket_t sock, struct addrinfo &ai) -> bool { + ipv6_v6only_, std::move(socket_options), + [&](socket_t sock, struct addrinfo &ai, bool & /*quit*/) -> bool { if (::bind(sock, ai.ai_addr, static_cast(ai.ai_addrlen))) { + output_error_log(Error::BindIPAddress, nullptr); + return false; + } + if (::listen(sock, CPPHTTPLIB_LISTEN_BACKLOG)) { + output_error_log(Error::Listen, nullptr); return false; } - if (::listen(sock, CPPHTTPLIB_LISTEN_BACKLOG)) { return false; } return true; }); } inline int Server::bind_internal(const std::string &host, int port, int socket_flags) { + if (is_decommissioned) { return -1; } + if (!is_valid()) { return -1; } svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_); @@ -6253,6 +8057,7 @@ inline int Server::bind_internal(const std::string &host, int port, socklen_t addr_len = sizeof(addr); if (getsockname(svr_sock_, reinterpret_cast(&addr), &addr_len) == -1) { + output_error_log(Error::GetSockName, nullptr); return -1; } if (addr.ss_family == AF_INET) { @@ -6260,6 +8065,7 @@ inline int Server::bind_internal(const std::string &host, int port, } else if (addr.ss_family == AF_INET6) { return ntohs(reinterpret_cast(&addr)->sin6_port); } else { + output_error_log(Error::UnsupportedAddressFamily, nullptr); return -1; } } else { @@ -6268,6 +8074,8 @@ inline int Server::bind_internal(const std::string &host, int port, } inline bool Server::listen_internal() { + if (is_decommissioned) { return false; } + auto ret = true; is_running_ = true; auto se = detail::scope_exit([&]() { is_running_ = false; }); @@ -6288,13 +8096,22 @@ inline bool Server::listen_internal() { #ifndef _WIN32 } #endif + +#if defined _WIN32 + // sockets connected via WASAccept inherit flags NO_HANDLE_INHERIT, + // OVERLAPPED + socket_t sock = WSAAccept(svr_sock_, nullptr, nullptr, nullptr, 0); +#elif defined SOCK_CLOEXEC + socket_t sock = accept4(svr_sock_, nullptr, nullptr, SOCK_CLOEXEC); +#else socket_t sock = accept(svr_sock_, nullptr, nullptr); +#endif 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)); + std::this_thread::sleep_for(std::chrono::microseconds{1}); continue; } else if (errno == EINTR || errno == EAGAIN) { continue; @@ -6302,48 +8119,30 @@ inline bool Server::listen_internal() { if (svr_sock_ != INVALID_SOCKET) { detail::close_socket(svr_sock_); ret = false; + output_error_log(Error::Connection, nullptr); } else { ; // The server socket was closed by user. } break; } - { -#ifdef _WIN32 - auto timeout = static_cast(read_timeout_sec_ * 1000 + - read_timeout_usec_ / 1000); - setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&timeout), sizeof(timeout)); -#else - timeval tv; - tv.tv_sec = static_cast(read_timeout_sec_); - tv.tv_usec = static_cast(read_timeout_usec_); - setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&tv), sizeof(tv)); -#endif - } - { + detail::set_socket_opt_time(sock, SOL_SOCKET, SO_RCVTIMEO, + read_timeout_sec_, read_timeout_usec_); + detail::set_socket_opt_time(sock, SOL_SOCKET, SO_SNDTIMEO, + write_timeout_sec_, write_timeout_usec_); -#ifdef _WIN32 - auto timeout = static_cast(write_timeout_sec_ * 1000 + - write_timeout_usec_ / 1000); - setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, - reinterpret_cast(&timeout), sizeof(timeout)); -#else - timeval tv; - tv.tv_sec = static_cast(write_timeout_sec_); - tv.tv_usec = static_cast(write_timeout_usec_); - setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, - reinterpret_cast(&tv), sizeof(tv)); -#endif + if (!task_queue->enqueue( + [this, sock]() { process_and_close_socket(sock); })) { + output_error_log(Error::ResourceExhaustion, nullptr); + detail::shutdown_socket(sock); + detail::close_socket(sock); } - - task_queue->enqueue([this, sock]() { process_and_close_socket(sock); }); } task_queue->shutdown(); } + is_decommissioned = !ret; return ret; } @@ -6354,9 +8153,8 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) { } // File handler - auto is_head_request = req.method == "HEAD"; - if ((req.method == "GET" || is_head_request) && - handle_file_request(req, res, is_head_request)) { + if ((req.method == "GET" || req.method == "HEAD") && + handle_file_request(req, res)) { return true; } @@ -6365,13 +8163,17 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) { { ContentReader reader( [&](ContentReceiver receiver) { - return read_content_with_content_receiver( + auto result = read_content_with_content_receiver( strm, req, res, std::move(receiver), nullptr, nullptr); + if (!result) { output_error_log(Error::Read, &req); } + return result; }, - [&](MultipartContentHeader header, ContentReceiver receiver) { - return read_content_with_content_receiver(strm, req, res, nullptr, - std::move(header), - std::move(receiver)); + [&](FormDataHeader header, ContentReceiver receiver) { + auto result = read_content_with_content_receiver( + strm, req, res, nullptr, std::move(header), + std::move(receiver)); + if (!result) { output_error_log(Error::Read, &req); } + return result; }); if (req.method == "POST") { @@ -6402,7 +8204,10 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) { } // Read content into `req.body` - if (!read_content(strm, req, res)) { return false; } + if (!read_content(strm, req, res)) { + output_error_log(Error::Read, &req); + return false; + } } // Regular handler @@ -6427,11 +8232,14 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) { inline bool Server::dispatch_request(Request &req, Response &res, const Handlers &handlers) const { for (const auto &x : handlers) { - const auto &pattern = x.first; + const auto &pattern = x.first; const auto &handler = x.second; - if (duckdb_re2::RegexMatch(req.path, req.matches, pattern)) { - handler(req, res); + if (duckdb_re2::RegexMatch(req.path, req.matches, pattern)) { + if (!pre_request_handler_ || + pre_request_handler_(req, res) != HandlerResponse::Handled) { + handler(req, res); + } return true; } } @@ -6441,15 +8249,15 @@ inline bool Server::dispatch_request(Request &req, Response &res, inline void Server::apply_ranges(const Request &req, Response &res, std::string &content_type, std::string &boundary) const { - if (req.ranges.size() > 1) { - boundary = detail::make_multipart_data_boundary(); - + if (req.ranges.size() > 1 && res.status == StatusCode::PartialContent_206) { auto it = res.headers.find("Content-Type"); if (it != res.headers.end()) { content_type = it->second; res.headers.erase(it); } + boundary = detail::make_multipart_data_boundary(); + res.set_header("Content-Type", "multipart/byteranges; boundary=" + boundary); } @@ -6459,19 +8267,20 @@ inline void Server::apply_ranges(const Request &req, Response &res, if (res.body.empty()) { if (res.content_length_ > 0) { size_t length = 0; - if (req.ranges.empty()) { + if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) { length = res.content_length_; } else if (req.ranges.size() == 1) { - auto offsets = - detail::get_range_offset_and_length(req, res.content_length_, 0); - length = offsets.second; + auto offset_and_length = detail::get_range_offset_and_length( + req.ranges[0], res.content_length_); + + length = offset_and_length.second; auto content_range = detail::make_content_range_header_field( - req.ranges[0], res.content_length_); + offset_and_length, res.content_length_); res.set_header("Content-Range", content_range); } else { - length = detail::get_multipart_ranges_data_length(req, res, boundary, - content_type); + length = detail::get_multipart_ranges_data_length( + req, boundary, content_type, res.content_length_); } res.set_header("Content-Length", std::to_string(length)); } else { @@ -6482,41 +8291,37 @@ inline void Server::apply_ranges(const Request &req, Response &res, res.set_header("Content-Encoding", "gzip"); } else if (type == detail::EncodingType::Brotli) { res.set_header("Content-Encoding", "br"); + } else if (type == detail::EncodingType::Zstd) { + res.set_header("Content-Encoding", "zstd"); } } } } } else { - if (req.ranges.empty()) { + if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) { ; } else if (req.ranges.size() == 1) { + auto offset_and_length = + detail::get_range_offset_and_length(req.ranges[0], res.body.size()); + auto offset = offset_and_length.first; + auto length = offset_and_length.second; + auto content_range = detail::make_content_range_header_field( - req.ranges[0], res.body.size()); + offset_and_length, res.body.size()); res.set_header("Content-Range", content_range); - auto offsets = - detail::get_range_offset_and_length(req, res.body.size(), 0); - auto offset = offsets.first; - auto length = offsets.second; - - if (offset < res.body.size()) { - res.body = res.body.substr(offset, length); - } else { - res.body.clear(); - res.status = StatusCode::RangeNotSatisfiable_416; - } + assert(offset + length <= res.body.size()); + res.body = res.body.substr(offset, length); } 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 = StatusCode::RangeNotSatisfiable_416; - } + detail::make_multipart_ranges_data(req, res, boundary, content_type, + res.body.size(), data); + res.body.swap(data); } if (type != detail::EncodingType::None) { + output_pre_compression_log(req, res); + duckdb::unique_ptr compressor; std::string content_encoding; @@ -6529,6 +8334,11 @@ inline void Server::apply_ranges(const Request &req, Response &res, #ifdef CPPHTTPLIB_BROTLI_SUPPORT compressor = detail::make_unique(); content_encoding = "br"; +#endif + } else if (type == detail::EncodingType::Zstd) { +#ifdef CPPHTTPLIB_ZSTD_SUPPORT + compressor = detail::make_unique(); + content_encoding = "zstd"; #endif } @@ -6554,19 +8364,58 @@ inline bool Server::dispatch_request_for_content_reader( Request &req, Response &res, ContentReader content_reader, const HandlersForContentReader &handlers) const { for (const auto &x : handlers) { - const auto &pattern = x.first; + const auto &pattern = x.first; const auto &handler = x.second; - if (duckdb_re2::RegexMatch(req.path, req.matches, pattern)) { - handler(req, res, content_reader); + if (duckdb_re2::RegexMatch(req.path, req.matches, pattern)) { + if (!pre_request_handler_ || + pre_request_handler_(req, res) != HandlerResponse::Handled) { + handler(req, res, content_reader); + } return true; } } return false; } +inline std::string +get_client_ip(const std::string &x_forwarded_for, + const std::vector &trusted_proxies) { + // X-Forwarded-For is a comma-separated list per RFC 7239 + std::vector ip_list; + detail::split(x_forwarded_for.data(), + x_forwarded_for.data() + x_forwarded_for.size(), ',', + [&](const char *b, const char *e) { + auto r = detail::trim(b, e, 0, static_cast(e - b)); + ip_list.emplace_back(std::string(b + r.first, b + r.second)); + }); + + for (size_t i = 0; i < ip_list.size(); ++i) { + auto ip = ip_list[i]; + + auto is_trusted_proxy = + std::any_of(trusted_proxies.begin(), trusted_proxies.end(), + [&](const std::string &proxy) { return ip == proxy; }); + + if (is_trusted_proxy) { + if (i == 0) { + // If the trusted proxy is the first IP, there's no preceding client IP + return ip; + } else { + // Return the IP immediately before the trusted proxy + return ip_list[i - 1]; + } + } + } + + // If no trusted proxy is found, return the first IP in the list + return ip_list.front(); +} + inline bool -Server::process_request(Stream &strm, bool close_connection, +Server::process_request(Stream &strm, const std::string &remote_addr, + int remote_port, const std::string &local_addr, + int local_port, bool close_connection, bool &connection_closed, const std::function &setup_request) { std::array buf{}; @@ -6577,37 +8426,43 @@ Server::process_request(Stream &strm, bool close_connection, if (!line_reader.getline()) { return false; } Request req; + req.start_time_ = std::chrono::steady_clock::now(); Response res; res.version = "HTTP/1.1"; res.headers = default_headers_; -#ifdef _WIN32 - // TODO: Increase FD_SETSIZE statically (libzmq), dynamically (MySQL). -#else -#ifndef CPPHTTPLIB_USE_POLL +#ifdef __APPLE__ // Socket file descriptor exceeded FD_SETSIZE... if (strm.socket() >= FD_SETSIZE) { Headers dummy; detail::read_headers(strm, dummy); res.status = StatusCode::InternalServerError_500; + output_error_log(Error::ExceedMaxSocketDescriptorCount, &req); 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 = StatusCode::UriTooLong_414; + // Request line and headers + if (!parse_request_line(line_reader.ptr(), req)) { + res.status = StatusCode::BadRequest_400; + output_error_log(Error::InvalidRequestLine, &req); 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)) { + // Request headers + if (!detail::read_headers(strm, req.headers)) { res.status = StatusCode::BadRequest_400; + output_error_log(Error::InvalidHeaders, &req); + return write_response(strm, close_connection, req, res); + } + + // Check if the request URI doesn't exceed the limit + if (req.target.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) { + Headers dummy; + detail::read_headers(strm, dummy); + res.status = StatusCode::UriTooLong_414; + output_error_log(Error::ExceedUriMaxLength, &req); return write_response(strm, close_connection, req, res); } @@ -6620,18 +8475,31 @@ Server::process_request(Stream &strm, bool close_connection, 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 (!trusted_proxies_.empty() && req.has_header("X-Forwarded-For")) { + auto x_forwarded_for = req.get_header_value("X-Forwarded-For"); + req.remote_addr = get_client_ip(x_forwarded_for, trusted_proxies_); + } else { + req.remote_addr = remote_addr; + } + req.remote_port = remote_port; + + req.local_addr = local_addr; + req.local_port = local_port; - strm.get_local_ip_and_port(req.local_addr, req.local_port); - req.set_header("LOCAL_ADDR", req.local_addr); - req.set_header("LOCAL_PORT", std::to_string(req.local_port)); + if (req.has_header("Accept")) { + const auto &accept_header = req.get_header_value("Accept"); + if (!detail::parse_accept_header(accept_header, req.accept_content_types)) { + res.status = StatusCode::BadRequest_400; + output_error_log(Error::HTTPParsing, &req); + return write_response(strm, close_connection, req, res); + } + } 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 = StatusCode::RangeNotSatisfiable_416; + output_error_log(Error::InvalidRangeHeader, &req); return write_response(strm, close_connection, req, res); } } @@ -6646,14 +8514,22 @@ Server::process_request(Stream &strm, bool close_connection, switch (status) { case StatusCode::Continue_100: case StatusCode::ExpectationFailed_417: - strm.write_format("HTTP/1.1 %d %s\r\n\r\n", status, - status_message(status)); + detail::write_response_line(strm, status); + strm.write("\r\n"); break; - default: return write_response(strm, close_connection, req, res); + default: + connection_closed = true; + return write_response(strm, true, req, res); } } - // Rounting + // Setup `is_connection_closed` method + auto sock = strm.socket(); + req.is_connection_closed = [sock]() { + return !detail::is_socket_alive(sock); + }; + + // Routing auto routed = false; #ifdef CPPHTTPLIB_NO_EXCEPTIONS routed = routing(req, res, strm); @@ -6689,15 +8565,51 @@ Server::process_request(Stream &strm, bool close_connection, } } #endif - if (routed) { if (res.status == -1) { res.status = req.ranges.empty() ? StatusCode::OK_200 : StatusCode::PartialContent_206; } + + // Serve file content by using a content provider + if (!res.file_content_path_.empty()) { + const auto &path = res.file_content_path_; + auto mm = duckdb::make_shared_ptr(path.c_str()); + if (!mm->is_open()) { + res.body.clear(); + res.content_length_ = 0; + res.content_provider_ = nullptr; + res.status = StatusCode::NotFound_404; + output_error_log(Error::OpenFile, &req); + return write_response(strm, close_connection, req, res); + } + + auto content_type = res.file_content_content_type_; + if (content_type.empty()) { + content_type = detail::find_content_type( + path, file_extension_and_mimetype_map_, default_file_mimetype_); + } + + res.set_content_provider( + mm->size(), content_type, + [mm](size_t offset, size_t length, DataSink &sink) -> bool { + sink.write(mm->data() + offset, length); + return true; + }); + } + + if (detail::range_error(req, res)) { + res.body.clear(); + res.content_length_ = 0; + res.content_provider_ = nullptr; + res.status = StatusCode::RangeNotSatisfiable_416; + return write_response(strm, close_connection, req, res); + } + return write_response_with_content(strm, close_connection, req, res); } else { if (res.status == -1) { res.status = StatusCode::NotFound_404; } + return write_response(strm, close_connection, req, res); } } @@ -6705,12 +8617,21 @@ Server::process_request(Stream &strm, bool close_connection, inline bool Server::is_valid() const { return true; } inline bool Server::process_and_close_socket(socket_t sock) { + std::string remote_addr; + int remote_port = 0; + detail::get_remote_ip_and_port(sock, remote_addr, remote_port); + + std::string local_addr; + int local_port = 0; + detail::get_local_ip_and_port(sock, local_addr, local_port); + 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, + [&](Stream &strm, bool close_connection, bool &connection_closed) { + return process_request(strm, remote_addr, remote_port, local_addr, + local_port, close_connection, connection_closed, nullptr); }); @@ -6719,6 +8640,29 @@ inline bool Server::process_and_close_socket(socket_t sock) { return ret; } +inline void Server::output_log(const Request &req, const Response &res) const { + if (logger_) { + std::lock_guard guard(logger_mutex_); + logger_(req, res); + } +} + +inline void Server::output_pre_compression_log(const Request &req, + const Response &res) const { + if (pre_compression_logger_) { + std::lock_guard guard(logger_mutex_); + pre_compression_logger_(req, res); + } +} + +inline void Server::output_error_log(const Error &err, + const Request *req) const { + if (error_logger_) { + std::lock_guard guard(logger_mutex_); + error_logger_(err, req); + } +} + // HTTP client implementation inline ClientImpl::ClientImpl(const std::string &host) : ClientImpl(host, 80, std::string(), std::string()) {} @@ -6729,11 +8673,21 @@ inline ClientImpl::ClientImpl(const std::string &host, int port) 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)), + : host_(detail::escape_abstract_namespace_unix_domain(host)), port_(port), + host_and_port_(detail::make_host_and_port_string(host_, port, is_ssl())), client_cert_path_(client_cert_path), client_key_path_(client_key_path) {} inline ClientImpl::~ClientImpl() { + // Wait until all the requests in flight are handled. + size_t retry_count = 10; + while (retry_count-- > 0) { + { + std::lock_guard guard(socket_mutex_); + if (socket_requests_in_flight_ == 0) { break; } + } + std::this_thread::sleep_for(std::chrono::milliseconds{1}); + } + std::lock_guard guard(socket_mutex_); shutdown_socket(socket_); close_socket(socket_); @@ -6749,6 +8703,7 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) { read_timeout_usec_ = rhs.read_timeout_usec_; write_timeout_sec_ = rhs.write_timeout_sec_; write_timeout_usec_ = rhs.write_timeout_usec_; + max_timeout_msec_ = rhs.max_timeout_msec_; basic_auth_username_ = rhs.basic_auth_username_; basic_auth_password_ = rhs.basic_auth_password_; bearer_token_auth_token_ = rhs.bearer_token_auth_token_; @@ -6758,9 +8713,10 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) { #endif keep_alive_ = rhs.keep_alive_; follow_location_ = rhs.follow_location_; - url_encode_ = rhs.url_encode_; + path_encode_ = rhs.path_encode_; address_family_ = rhs.address_family_; tcp_nodelay_ = rhs.tcp_nodelay_; + ipv6_v6only_ = rhs.ipv6_v6only_; socket_options_ = rhs.socket_options_; compress_ = rhs.compress_; decompress_ = rhs.decompress_; @@ -6781,17 +8737,20 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) { #endif #ifdef CPPHTTPLIB_OPENSSL_SUPPORT server_certificate_verification_ = rhs.server_certificate_verification_; + server_hostname_verification_ = rhs.server_hostname_verification_; + server_certificate_verifier_ = rhs.server_certificate_verifier_; #endif logger_ = rhs.logger_; + error_logger_ = rhs.error_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_, std::string(), 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); + ipv6_v6only_, 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_ @@ -6800,10 +8759,10 @@ inline socket_t ClientImpl::create_client_socket(Error &error) const { if (it != addr_map_.end()) { ip = it->second; } return detail::create_client_socket( - host_, ip, 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); + host_, ip, port_, address_family_, tcp_nodelay_, ipv6_v6only_, + 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, @@ -6855,9 +8814,9 @@ inline bool ClientImpl::read_response_line(Stream &strm, const Request &req, if (!line_reader.getline()) { return false; } #ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR - const Regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n"); + thread_local const Regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n"); #else - const Regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n"); + thread_local const Regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n"); #endif Match m; @@ -6896,18 +8855,28 @@ inline bool ClientImpl::send_(Request &req, Response &res, Error &error) { { std::lock_guard 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. + // 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); + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + if (is_alive && is_ssl()) { + if (detail::is_ssl_peer_could_be_closed(socket_.ssl, socket_.sock)) { + is_alive = false; + } + } +#endif + 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 + // Attempt to avoid sigpipe by shutting down non-gracefully 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_); @@ -6916,7 +8885,10 @@ inline bool ClientImpl::send_(Request &req, Response &res, Error &error) { } if (!is_alive) { - if (!create_and_connect_socket(socket_, error)) { return false; } + if (!create_and_connect_socket(socket_, error)) { + output_error_log(error, &req); + return false; + } #ifdef CPPHTTPLIB_OPENSSL_SUPPORT // TODO: refactoring @@ -6924,12 +8896,17 @@ inline bool ClientImpl::send_(Request &req, Response &res, Error &error) { auto &scli = static_cast(*this); if (!proxy_host_.empty() && proxy_port_ != -1) { auto success = false; - if (!scli.connect_with_proxy(socket_, res, success, error)) { + if (!scli.connect_with_proxy(socket_, req.start_time_, res, success, + error)) { + if (!success) { output_error_log(error, &req); } return success; } } - if (!scli.initialize_ssl(socket_, error)) { return false; } + if (!scli.initialize_ssl(socket_, error)) { + output_error_log(error, &req); + return false; + } } #endif } @@ -6970,12 +8947,15 @@ inline bool ClientImpl::send_(Request &req, Response &res, Error &error) { } }); - ret = process_socket(socket_, [&](Stream &strm) { + ret = process_socket(socket_, req.start_time_, [&](Stream &strm) { return handle_request(strm, req, res, close_connection, error); }); if (!ret) { - if (error == Error::Success) { error = Error::Unknown; } + if (error == Error::Success) { + error = Error::Unknown; + output_error_log(error, &req); + } } return ret; @@ -6990,7 +8970,12 @@ inline Result ClientImpl::send_(Request &&req) { auto res = detail::make_unique(); auto error = Error::Success; auto ret = send(req, *res, error); +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers), + last_ssl_error_, last_openssl_error_}; +#else return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers)}; +#endif } inline bool ClientImpl::handle_request(Stream &strm, Request &req, @@ -6998,6 +8983,7 @@ inline bool ClientImpl::handle_request(Stream &strm, Request &req, Error &error) { if (req.path.empty()) { error = Error::Connection; + output_error_log(error, &req); return false; } @@ -7073,19 +9059,20 @@ inline bool ClientImpl::handle_request(Stream &strm, Request &req, inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) { if (req.redirect_count_ == 0) { error = Error::ExceedRedirectCount; + output_error_log(error, &req); return false; } auto location = res.get_header_value("location"); - if (location.empty()) { - // s3 requests will not return a location header, and instead a - // X-Amx-Region-Bucket header. Return true so all response headers - // are returned to the httpfs/calling extension - return true; - } + if (location.empty()) { + // s3 requests will not return a location header, and instead a + // X-Amx-Region-Bucket header. Return true so all response headers + // are returned to the httpfs/calling extension + return true; + } - const Regex re( - R"((?:(https?):)?(?://(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)"); + thread_local const Regex re( + R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)"); Match m; if (!RegexMatch(location, m, re)) { return false; } @@ -7109,27 +9096,158 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) { if (next_scheme.empty()) { next_scheme = scheme; } if (next_host.empty()) { next_host = host_; } if (next_path.empty()) { next_path = "/"; } - - auto path = detail::decode_url(next_path, true, std::set {'/'}) + next_query; - + + auto path = decode_query_component(next_path, true) + next_query; + + // Same host redirect - use current client if (next_scheme == scheme && next_host == host_ && next_port == port_) { return detail::redirect(*this, req, res, path, location, error); - } else { - if (next_scheme == "https") { + } + + // Cross-host/scheme redirect - create new client with robust setup + return create_redirect_client(next_scheme, next_host, next_port, req, res, + path, location, error); +} + +// New method for robust redirect client creation +inline bool ClientImpl::create_redirect_client( + const std::string &scheme, const std::string &host, int port, Request &req, + Response &res, const std::string &path, const std::string &location, + Error &error) { + // Determine if we need SSL + auto need_ssl = (scheme == "https"); + + // Clean up request headers that are host/client specific + // Remove headers that should not be carried over to new host + auto headers_to_remove = + std::vector{"Host", "Proxy-Authorization", "Authorization"}; + + for (const auto &header_name : headers_to_remove) { + auto it = req.headers.find(header_name); + while (it != req.headers.end()) { + it = req.headers.erase(it); + it = req.headers.find(header_name); + } + } + + // Create appropriate client type and handle redirect + if (need_ssl) { #ifdef CPPHTTPLIB_OPENSSL_SUPPORT - SSLClient cli(next_host, next_port); - cli.copy_settings(*this); - if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); } - return detail::redirect(cli, req, res, path, location, error); + // Create SSL client for HTTPS redirect + SSLClient redirect_client(host, port); + + // Setup basic client configuration first + setup_redirect_client(redirect_client); + + // SSL-specific configuration for proxy environments + if (!proxy_host_.empty() && proxy_port_ != -1) { + // Critical: Disable SSL verification for proxy environments + redirect_client.enable_server_certificate_verification(false); + redirect_client.enable_server_hostname_verification(false); + } else { + // For direct SSL connections, copy SSL verification settings + redirect_client.enable_server_certificate_verification( + server_certificate_verification_); + redirect_client.enable_server_hostname_verification( + server_hostname_verification_); + } + + // Handle CA certificate store and paths if available + if (ca_cert_store_ && X509_STORE_up_ref(ca_cert_store_)) { + redirect_client.set_ca_cert_store(ca_cert_store_); + } + if (!ca_cert_file_path_.empty()) { + redirect_client.set_ca_cert_path(ca_cert_file_path_, ca_cert_dir_path_); + } + + // Client certificates are set through constructor for SSLClient + // NOTE: SSLClient constructor already takes client_cert_path and + // client_key_path so we need to create it properly if client certs are + // needed + + // Execute the redirect + return detail::redirect(redirect_client, req, res, path, location, error); #else - return false; + // SSL not supported - set appropriate error + error = Error::SSLConnection; + output_error_log(error, &req); + return false; #endif - } else { - ClientImpl cli(next_host, next_port); - cli.copy_settings(*this); - return detail::redirect(cli, req, res, path, location, error); + } else { + // HTTP redirect + ClientImpl redirect_client(host, port); + + // Setup client with robust configuration + setup_redirect_client(redirect_client); + + // Execute the redirect + return detail::redirect(redirect_client, req, res, path, location, error); + } +} + +// New method for robust client setup (based on basic_manual_redirect.cpp +// logic) +template +inline void ClientImpl::setup_redirect_client(ClientType &client) { + // Copy basic settings first + client.set_connection_timeout(connection_timeout_sec_); + client.set_read_timeout(read_timeout_sec_, read_timeout_usec_); + client.set_write_timeout(write_timeout_sec_, write_timeout_usec_); + client.set_keep_alive(keep_alive_); + client.set_follow_location( + true); // Enable redirects to handle multi-step redirects + client.set_path_encode(path_encode_); + client.set_compress(compress_); + client.set_decompress(decompress_); + + // Copy authentication settings BEFORE proxy setup + if (!basic_auth_username_.empty()) { + client.set_basic_auth(basic_auth_username_, basic_auth_password_); + } + if (!bearer_token_auth_token_.empty()) { + client.set_bearer_token_auth(bearer_token_auth_token_); + } +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + if (!digest_auth_username_.empty()) { + client.set_digest_auth(digest_auth_username_, digest_auth_password_); + } +#endif + + // Setup proxy configuration (CRITICAL ORDER - proxy must be set + // before proxy auth) + if (!proxy_host_.empty() && proxy_port_ != -1) { + // First set proxy host and port + client.set_proxy(proxy_host_, proxy_port_); + + // Then set proxy authentication (order matters!) + if (!proxy_basic_auth_username_.empty()) { + client.set_proxy_basic_auth(proxy_basic_auth_username_, + proxy_basic_auth_password_); + } + if (!proxy_bearer_token_auth_token_.empty()) { + client.set_proxy_bearer_token_auth(proxy_bearer_token_auth_token_); + } +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + if (!proxy_digest_auth_username_.empty()) { + client.set_proxy_digest_auth(proxy_digest_auth_username_, + proxy_digest_auth_password_); } +#endif } + + // Copy network and socket settings + client.set_address_family(address_family_); + client.set_tcp_nodelay(tcp_nodelay_); + client.set_ipv6_v6only(ipv6_v6only_); + if (socket_options_) { client.set_socket_options(socket_options_); } + if (!interface_.empty()) { client.set_interface(interface_); } + + // Copy logging and headers + if (logger_) { client.set_logger(logger_); } + if (error_logger_) { client.set_error_logger(error_logger_); } + + // NOTE: DO NOT copy default_headers_ as they may contain stale Host headers + // Each new client should generate its own headers based on its target host } inline bool ClientImpl::write_content_with_provider(Stream &strm, @@ -7152,8 +9270,9 @@ inline bool ClientImpl::write_content_with_provider(Stream &strm, 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); + return detail::write_content_with_progress( + strm, req.content_provider_, 0, req.content_length_, is_shutting_down, + req.upload_progress, error); } } @@ -7167,29 +9286,41 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req, } if (!req.has_header("Host")) { - if (is_ssl()) { - if (port_ == 443) { - req.set_header("Host", host_); - } else { - req.set_header("Host", host_and_port_); - } + // For Unix socket connections, use "localhost" as Host header (similar to + // curl behavior) + if (address_family_ == AF_UNIX) { + req.set_header("Host", "localhost"); } else { - if (port_ == 80) { - req.set_header("Host", host_); - } else { - req.set_header("Host", host_and_port_); - } + req.set_header("Host", host_and_port_); } } if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); } + if (!req.content_receiver) { + if (!req.has_header("Accept-Encoding")) { + std::string accept_encoding; +#ifdef CPPHTTPLIB_BROTLI_SUPPORT + accept_encoding = "br"; +#endif +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + if (!accept_encoding.empty()) { accept_encoding += ", "; } + accept_encoding += "gzip, deflate"; +#endif +#ifdef CPPHTTPLIB_ZSTD_SUPPORT + if (!accept_encoding.empty()) { accept_encoding += ", "; } + accept_encoding += "zstd"; +#endif + req.set_header("Accept-Encoding", accept_encoding); + } + #ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT - if (!req.has_header("User-Agent")) { - auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION; - req.set_header("User-Agent", agent); - } + if (!req.has_header("User-Agent")) { + auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION; + req.set_header("User-Agent", agent); + } #endif + }; if (req.body.empty()) { if (req.content_provider_) { @@ -7249,15 +9380,35 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req, { 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()); + // Extract path and query from req.path + std::string path_part, query_part; + auto query_pos = req.path.find('?'); + if (query_pos != std::string::npos) { + path_part = req.path.substr(0, query_pos); + query_part = req.path.substr(query_pos + 1); + } else { + path_part = req.path; + query_part = ""; + } + + // Encode path and query + auto path_with_query = + path_encode_ ? detail::encode_path(path_part) : path_part; + + detail::parse_query_text(query_part, req.params); + if (!req.params.empty()) { + path_with_query = append_query_params(path_with_query, req.params); + } + // Write request line and headers + detail::write_request_line(bstrm, req.method, path_with_query); header_writer_(bstrm, req.headers); // Flush buffer auto &data = bstrm.get_buffer(); if (!detail::write_data(strm, data.data(), data.size())) { error = Error::Write; + output_error_log(error, &req); return false; } } @@ -7267,9 +9418,32 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req, return write_content_with_provider(strm, req, error); } - if (!detail::write_data(strm, req.body.data(), req.body.size())) { - error = Error::Write; - return false; + if (req.upload_progress) { + auto body_size = req.body.size(); + size_t written = 0; + auto data = req.body.data(); + + while (written < body_size) { + size_t to_write = (std::min)(CPPHTTPLIB_SEND_BUFSIZ, body_size - written); + if (!detail::write_data(strm, data + written, to_write)) { + error = Error::Write; + output_error_log(error, &req); + return false; + } + written += to_write; + + if (!req.upload_progress(written, body_size)) { + error = Error::Canceled; + output_error_log(error, &req); + return false; + } + } + } else { + if (!detail::write_data(strm, req.body.data(), req.body.size())) { + error = Error::Write; + output_error_log(error, &req); + return false; + } } return true; @@ -7319,6 +9493,7 @@ inline duckdb::unique_ptr ClientImpl::send_with_content_provider( while (ok && offset < content_length) { if (!content_provider(offset, content_length - offset, data_sink)) { error = Error::Canceled; + output_error_log(error, &req); return nullptr; } } @@ -7329,6 +9504,7 @@ inline duckdb::unique_ptr ClientImpl::send_with_content_provider( return true; })) { error = Error::Compression; + output_error_log(error, &req); return nullptr; } } @@ -7358,11 +9534,15 @@ inline Result ClientImpl::send_with_content_provider( const std::string &method, const std::string &path, const Headers &headers, const char *body, size_t content_length, ContentProvider content_provider, ContentProviderWithoutLength content_provider_without_length, - const std::string &content_type) { + const std::string &content_type, UploadProgress progress) { Request req; req.method = method; req.headers = headers; req.path = path; + req.upload_progress = std::move(progress); + if (max_timeout_msec_ > 0) { + req.start_time_ = std::chrono::steady_clock::now(); + } auto error = Error::Success; @@ -7370,13 +9550,28 @@ inline Result ClientImpl::send_with_content_provider( req, body, content_length, std::move(content_provider), std::move(content_provider_without_length), content_type, error); +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + return Result{std::move(res), error, std::move(req.headers), last_ssl_error_, + last_openssl_error_}; +#else return Result{std::move(res), error, std::move(req.headers)}; +#endif } -inline std::string -ClientImpl::adjust_host_string(const std::string &host) const { - if (host.find(':') != std::string::npos) { return "[" + host + "]"; } - return host; +inline void ClientImpl::output_log(const Request &req, + const Response &res) const { + if (logger_) { + std::lock_guard guard(logger_mutex_); + logger_(req, res); + } +} + +inline void ClientImpl::output_error_log(const Error &err, + const Request *req) const { + if (error_logger_) { + std::lock_guard guard(logger_mutex_); + error_logger_(err, req); + } } inline bool ClientImpl::process_request(Stream &strm, Request &req, @@ -7389,10 +9584,9 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req, if (is_ssl()) { auto is_proxy_enabled = !proxy_host_.empty() && proxy_port_ != -1; if (!is_proxy_enabled) { - char buf[1]; - if (SSL_peek(socket_.ssl, buf, 1) == 0 && - SSL_get_error(socket_.ssl, 0) == SSL_ERROR_ZERO_RETURN) { + if (detail::is_ssl_peer_could_be_closed(socket_.ssl, socket_.sock)) { error = Error::SSLPeerCouldBeClosed_; + output_error_log(error, &req); return false; } } @@ -7403,17 +9597,21 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req, if (!read_response_line(strm, req, res) || !detail::read_headers(strm, res.headers)) { error = Error::Read; + output_error_log(error, &req); return false; } // Body if ((res.status != StatusCode::NoContent_204) && req.method != "HEAD" && req.method != "CONNECT") { - auto redirect = 300 < res.status && res.status < 400 && follow_location_; + auto redirect = 300 < res.status && res.status < 400 && + res.status != StatusCode::NotModified_304 && + follow_location_; if (req.response_handler && !redirect) { if (!req.response_handler(res)) { error = Error::Canceled; + output_error_log(error, &req); return false; } } @@ -7421,51 +9619,70 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req, auto out = req.content_receiver ? static_cast( - [&](const char *buf, size_t n, uint64_t off, uint64_t len) { + [&](const char *buf, size_t n, size_t off, size_t len) { if (redirect) { return true; } auto ret = req.content_receiver(buf, n, off, len); - if (!ret) { error = Error::Canceled; } + if (!ret) { + error = Error::Canceled; + output_error_log(error, &req); + } return ret; }) : static_cast( - [&](const char *buf, size_t n, uint64_t /*off*/, - uint64_t /*len*/) { - if (res.body.size() + n > res.body.max_size()) { - return false; - } + [&](const char *buf, size_t n, size_t /*off*/, + size_t /*len*/) { + assert(res.body.size() + n <= res.body.max_size()); 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; } + auto progress = [&](size_t current, size_t total) { + if (!req.download_progress || redirect) { return true; } + auto ret = req.download_progress(current, total); + if (!ret) { + error = Error::Canceled; + output_error_log(error, &req); + } return ret; }; - int dummy_status; - if (!detail::read_content(strm, res, (std::numeric_limits::max)(), - dummy_status, std::move(progress), std::move(out), - decompress_)) { - if (error != Error::Canceled) { error = Error::Read; } - return false; + if (res.has_header("Content-Length")) { + if (!req.content_receiver) { + auto len = res.get_header_value_u64("Content-Length"); + if (len > res.body.max_size()) { + error = Error::Read; + output_error_log(error, &req); + return false; + } + res.body.reserve(static_cast(len)); + } + } + + if (res.status != StatusCode::NotModified_304) { + int dummy_status; + if (!detail::read_content(strm, res, (std::numeric_limits::max)(), + dummy_status, std::move(progress), + std::move(out), decompress_)) { + if (error != Error::Canceled) { error = Error::Read; } + output_error_log(error, &req); + return false; + } } } // Log - if (logger_) { logger_(req, res); } + output_log(req, res); return true; } inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider( - const std::string &boundary, const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) const { + const std::string &boundary, const UploadFormDataItems &items, + const FormDataProviderItems &provider_items) const { size_t cur_item = 0; size_t cur_start = 0; - // cur_item and cur_start are copied to within the std::function and maintain - // state between successive calls + // cur_item and cur_start are copied to within the std::function and + // maintain state between successive calls return [&, cur_item, cur_start](size_t offset, DataSink &sink) mutable -> bool { if (!offset && !items.empty()) { @@ -7503,81 +9720,63 @@ inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider( }; } -inline bool -ClientImpl::process_socket(const Socket &socket, - std::function callback) { +inline bool ClientImpl::process_socket( + const Socket &socket, + std::chrono::time_point start_time, + std::function callback) { return detail::process_client_socket( socket.sock, read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, - write_timeout_usec_, std::move(callback)); + write_timeout_usec_, max_timeout_msec_, start_time, std::move(callback)); } inline bool ClientImpl::is_ssl() const { return false; } -inline Result ClientImpl::Get(const std::string &path) { - return Get(path, Headers(), Progress()); -} - -inline Result ClientImpl::Get(const std::string &path, Progress progress) { +inline Result ClientImpl::Get(const std::string &path, + DownloadProgress progress) { return Get(path, Headers(), std::move(progress)); } -inline Result ClientImpl::Get(const std::string &path, const Headers &headers) { - return Get(path, headers, Progress()); +inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, + const Headers &headers, + DownloadProgress progress) { + if (params.empty()) { return Get(path, headers); } + + std::string path_with_query = append_query_params(path, params); + return Get(path_with_query, headers, std::move(progress)); } inline Result ClientImpl::Get(const std::string &path, const Headers &headers, - Progress progress) { + DownloadProgress progress) { Request req; req.method = "GET"; req.path = path; req.headers = headers; - req.progress = std::move(progress); + req.download_progress = std::move(progress); + if (max_timeout_msec_ > 0) { + req.start_time_ = std::chrono::steady_clock::now(); + } return send_(std::move(req)); } -inline Result ClientImpl::Get(const std::string &path, - ContentReceiver content_receiver) { - return Get(path, Headers(), nullptr, std::move(content_receiver), nullptr); -} - inline Result ClientImpl::Get(const std::string &path, ContentReceiver content_receiver, - Progress progress) { + DownloadProgress progress) { return Get(path, Headers(), nullptr, std::move(content_receiver), std::move(progress)); } -inline Result ClientImpl::Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver) { - return Get(path, headers, nullptr, std::move(content_receiver), nullptr); -} - inline Result ClientImpl::Get(const std::string &path, const Headers &headers, ContentReceiver content_receiver, - Progress progress) { + DownloadProgress progress) { return Get(path, headers, nullptr, std::move(content_receiver), std::move(progress)); } -inline Result ClientImpl::Get(const std::string &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 std::string &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 std::string &path, ResponseHandler response_handler, ContentReceiver content_receiver, - Progress progress) { + DownloadProgress progress) { return Get(path, Headers(), std::move(response_handler), std::move(content_receiver), std::move(progress)); } @@ -7585,7 +9784,7 @@ inline Result ClientImpl::Get(const std::string &path, inline Result ClientImpl::Get(const std::string &path, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, - Progress progress) { + DownloadProgress progress) { Request req; req.method = "GET"; req.path = path; @@ -7593,41 +9792,38 @@ inline Result ClientImpl::Get(const std::string &path, const 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*/) { + size_t /*offset*/, size_t /*total_length*/) { return content_receiver(data, data_length); }; - req.progress = std::move(progress); + req.download_progress = std::move(progress); + if (max_timeout_msec_ > 0) { + req.start_time_ = std::chrono::steady_clock::now(); + } return send_(std::move(req)); } -inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, - 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, headers, progress); -} - inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, const Headers &headers, ContentReceiver content_receiver, - Progress progress) { - return Get(path, params, headers, nullptr, content_receiver, progress); + DownloadProgress progress) { + return Get(path, params, headers, nullptr, std::move(content_receiver), + std::move(progress)); } inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, const Headers &headers, ResponseHandler response_handler, ContentReceiver content_receiver, - Progress progress) { + DownloadProgress progress) { if (params.empty()) { - return Get(path, headers, response_handler, content_receiver, progress); + return Get(path, headers, std::move(response_handler), + std::move(content_receiver), std::move(progress)); } std::string path_with_query = append_query_params(path, params); - return Get(path_with_query, headers, response_handler, content_receiver, - progress); + return Get(path_with_query, headers, std::move(response_handler), + std::move(content_receiver), std::move(progress)); } inline Result ClientImpl::Head(const std::string &path) { @@ -7640,6 +9836,9 @@ inline Result ClientImpl::Head(const std::string &path, req.method = "HEAD"; req.headers = headers; req.path = path; + if (max_timeout_msec_ > 0) { + req.start_time_ = std::chrono::steady_clock::now(); + } return send_(std::move(req)); } @@ -7655,28 +9854,15 @@ inline Result ClientImpl::Post(const std::string &path, inline Result ClientImpl::Post(const std::string &path, const char *body, size_t content_length, - const std::string &content_type) { - return Post(path, Headers(), body, content_length, content_type); -} - -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type) { - return send_with_content_provider("POST", path, headers, body, content_length, - nullptr, nullptr, content_type); + const std::string &content_type, + UploadProgress progress) { + return Post(path, Headers(), body, content_length, content_type, progress); } inline Result ClientImpl::Post(const std::string &path, const std::string &body, - const std::string &content_type) { - return Post(path, Headers(), body, content_type); -} - -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - const std::string &body, - const std::string &content_type) { - return send_with_content_provider("POST", path, headers, body.data(), - body.size(), nullptr, nullptr, - content_type); + const std::string &content_type, + UploadProgress progress) { + return Post(path, Headers(), body, content_type, progress); } inline Result ClientImpl::Post(const std::string &path, const Params ¶ms) { @@ -7685,31 +9871,18 @@ inline Result ClientImpl::Post(const std::string &path, const Params ¶ms) { inline Result ClientImpl::Post(const std::string &path, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return Post(path, Headers(), content_length, std::move(content_provider), - content_type); + content_type, progress); } inline Result ClientImpl::Post(const std::string &path, ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return Post(path, Headers(), std::move(content_provider), content_type); -} - -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - size_t content_length, - ContentProvider content_provider, - const std::string &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 std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr, - std::move(content_provider), content_type); + const std::string &content_type, + UploadProgress progress) { + return Post(path, Headers(), std::move(content_provider), content_type, + progress); } inline Result ClientImpl::Post(const std::string &path, const Headers &headers, @@ -7719,22 +9892,25 @@ inline Result ClientImpl::Post(const std::string &path, const Headers &headers, } inline Result ClientImpl::Post(const std::string &path, - const MultipartFormDataItems &items) { - return Post(path, Headers(), items); + const UploadFormDataItems &items, + UploadProgress progress) { + return Post(path, Headers(), items, progress); } inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items) { + const UploadFormDataItems &items, + UploadProgress progress) { const auto &boundary = detail::make_multipart_data_boundary(); const auto &content_type = detail::serialize_multipart_formdata_get_content_type(boundary); const auto &body = detail::serialize_multipart_formdata(items, boundary); - return Post(path, headers, body, content_type); + return Post(path, headers, body, content_type, progress); } inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string &boundary) { + const UploadFormDataItems &items, + const std::string &boundary, + UploadProgress progress) { if (!detail::is_multipart_boundary_chars_valid(boundary)) { return Result{nullptr, Error::UnsupportedMultipartBoundaryChars}; } @@ -7742,108 +9918,305 @@ inline Result ClientImpl::Post(const std::string &path, const Headers &headers, const auto &content_type = detail::serialize_multipart_formdata_get_content_type(boundary); const auto &body = detail::serialize_multipart_formdata(items, boundary); - return Post(path, headers, body, content_type); + return Post(path, headers, body, content_type, progress); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, + UploadProgress progress) { + return send_with_content_provider("POST", path, headers, body, content_length, + nullptr, nullptr, content_type, progress); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + UploadProgress progress) { + return send_with_content_provider("POST", path, headers, body.data(), + body.size(), nullptr, nullptr, content_type, + progress); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + size_t content_length, + ContentProvider content_provider, + const std::string &content_type, + UploadProgress progress) { + return send_with_content_provider("POST", path, headers, nullptr, + content_length, std::move(content_provider), + nullptr, content_type, progress); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + ContentProviderWithoutLength content_provider, + const std::string &content_type, + UploadProgress progress) { + return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr, + std::move(content_provider), content_type, + progress); } -inline Result -ClientImpl::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) { +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + const FormDataProviderItems &provider_items, + UploadProgress progress) { const auto &boundary = detail::make_multipart_data_boundary(); const auto &content_type = detail::serialize_multipart_formdata_get_content_type(boundary); return send_with_content_provider( "POST", path, headers, nullptr, 0, nullptr, get_multipart_content_provider(boundary, items, provider_items), - content_type); + content_type, progress); +} + +inline Result ClientImpl::Post(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + ContentReceiver content_receiver, + DownloadProgress progress) { + Request req; + req.method = "POST"; + req.path = path; + req.headers = headers; + req.body = body; + req.content_receiver = + [content_receiver](const char *data, size_t data_length, + size_t /*offset*/, size_t /*total_length*/) { + return content_receiver(data, data_length); + }; + req.download_progress = std::move(progress); + + if (max_timeout_msec_ > 0) { + req.start_time_ = std::chrono::steady_clock::now(); + } + + if (!content_type.empty()) { req.set_header("Content-Type", content_type); } + + return send_(std::move(req)); } inline Result ClientImpl::Put(const std::string &path) { return Put(path, std::string(), std::string()); } -inline Result ClientImpl::Put(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return Put(path, Headers(), body, content_length, content_type); +inline Result ClientImpl::Put(const std::string &path, const Headers &headers) { + return Put(path, headers, nullptr, 0, std::string()); } -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type) { - return send_with_content_provider("PUT", path, headers, body, content_length, - nullptr, nullptr, content_type); +inline Result ClientImpl::Put(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type, + UploadProgress progress) { + return Put(path, Headers(), body, content_length, content_type, progress); } inline Result ClientImpl::Put(const std::string &path, const std::string &body, - const std::string &content_type) { - return Put(path, Headers(), body, content_type); + const std::string &content_type, + UploadProgress progress) { + return Put(path, Headers(), body, content_type, progress); } -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const std::string &body, - const std::string &content_type) { - return send_with_content_provider("PUT", path, headers, body.data(), - body.size(), nullptr, nullptr, - content_type); +inline Result ClientImpl::Put(const std::string &path, const Params ¶ms) { + return Put(path, Headers(), params); } inline Result ClientImpl::Put(const std::string &path, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return Put(path, Headers(), content_length, std::move(content_provider), - content_type); + content_type, progress); } inline Result ClientImpl::Put(const std::string &path, ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return Put(path, Headers(), std::move(content_provider), content_type); + const std::string &content_type, + UploadProgress progress) { + return Put(path, Headers(), std::move(content_provider), content_type, + progress); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const Params ¶ms) { + auto query = detail::params_to_query_str(params); + return Put(path, headers, query, "application/x-www-form-urlencoded"); +} + +inline Result ClientImpl::Put(const std::string &path, + const UploadFormDataItems &items, + UploadProgress progress) { + return Put(path, Headers(), items, progress); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + UploadProgress progress) { + const auto &boundary = detail::make_multipart_data_boundary(); + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + const auto &body = detail::serialize_multipart_formdata(items, boundary); + return Put(path, headers, body, content_type, progress); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + const std::string &boundary, + UploadProgress progress) { + if (!detail::is_multipart_boundary_chars_valid(boundary)) { + return Result{nullptr, Error::UnsupportedMultipartBoundaryChars}; + } + + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + const auto &body = detail::serialize_multipart_formdata(items, boundary); + return Put(path, headers, body, content_type, progress); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const char *body, size_t content_length, + const std::string &content_type, + UploadProgress progress) { + return send_with_content_provider("PUT", path, headers, body, content_length, + nullptr, nullptr, content_type, progress); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + UploadProgress progress) { + return send_with_content_provider("PUT", path, headers, body.data(), + body.size(), nullptr, nullptr, content_type, + progress); } inline Result ClientImpl::Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return send_with_content_provider("PUT", path, headers, nullptr, content_length, std::move(content_provider), - nullptr, content_type); + nullptr, content_type, progress); } inline Result ClientImpl::Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr, - std::move(content_provider), content_type); + std::move(content_provider), content_type, + progress); } -inline Result ClientImpl::Put(const std::string &path, const Params ¶ms) { - return Put(path, Headers(), params); +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + const FormDataProviderItems &provider_items, + UploadProgress progress) { + const auto &boundary = detail::make_multipart_data_boundary(); + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + return send_with_content_provider( + "PUT", path, headers, nullptr, 0, nullptr, + get_multipart_content_provider(boundary, items, provider_items), + content_type, progress); +} + +inline Result ClientImpl::Put(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + ContentReceiver content_receiver, + DownloadProgress progress) { + Request req; + req.method = "PUT"; + req.path = path; + req.headers = headers; + req.body = body; + req.content_receiver = + [content_receiver](const char *data, size_t data_length, + size_t /*offset*/, size_t /*total_length*/) { + return content_receiver(data, data_length); + }; + req.download_progress = std::move(progress); + + if (max_timeout_msec_ > 0) { + req.start_time_ = std::chrono::steady_clock::now(); + } + + if (!content_type.empty()) { req.set_header("Content-Type", content_type); } + + return send_(std::move(req)); +} + +inline Result ClientImpl::Patch(const std::string &path) { + return Patch(path, std::string(), std::string()); +} + +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + UploadProgress progress) { + return Patch(path, headers, nullptr, 0, std::string(), progress); +} + +inline Result ClientImpl::Patch(const std::string &path, const char *body, + size_t content_length, + const std::string &content_type, + UploadProgress progress) { + return Patch(path, Headers(), body, content_length, content_type, progress); +} + +inline Result ClientImpl::Patch(const std::string &path, + const std::string &body, + const std::string &content_type, + UploadProgress progress) { + return Patch(path, Headers(), body, content_type, progress); +} + +inline Result ClientImpl::Patch(const std::string &path, const Params ¶ms) { + return Patch(path, Headers(), params); +} + +inline Result ClientImpl::Patch(const std::string &path, size_t content_length, + ContentProvider content_provider, + const std::string &content_type, + UploadProgress progress) { + return Patch(path, Headers(), content_length, std::move(content_provider), + content_type, progress); +} + +inline Result ClientImpl::Patch(const std::string &path, + ContentProviderWithoutLength content_provider, + const std::string &content_type, + UploadProgress progress) { + return Patch(path, Headers(), std::move(content_provider), content_type, + progress); } -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const Params ¶ms) { +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + const Params ¶ms) { auto query = detail::params_to_query_str(params); - return Put(path, headers, query, "application/x-www-form-urlencoded"); + return Patch(path, headers, query, "application/x-www-form-urlencoded"); } -inline Result ClientImpl::Put(const std::string &path, - const MultipartFormDataItems &items) { - return Put(path, Headers(), items); +inline Result ClientImpl::Patch(const std::string &path, + const UploadFormDataItems &items, + UploadProgress progress) { + return Patch(path, Headers(), items, progress); } -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items) { +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + UploadProgress progress) { const auto &boundary = detail::make_multipart_data_boundary(); const auto &content_type = detail::serialize_multipart_formdata_get_content_type(boundary); const auto &body = detail::serialize_multipart_formdata(items, boundary); - return Put(path, headers, body, content_type); + return Patch(path, headers, body, content_type, progress); } -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string &boundary) { +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + const std::string &boundary, + UploadProgress progress) { if (!detail::is_multipart_boundary_chars_valid(boundary)) { return Result{nullptr, Error::UnsupportedMultipartBoundaryChars}; } @@ -7851,105 +10224,146 @@ inline Result ClientImpl::Put(const std::string &path, const Headers &headers, const auto &content_type = detail::serialize_multipart_formdata_get_content_type(boundary); const auto &body = detail::serialize_multipart_formdata(items, boundary); - return Put(path, headers, body, content_type); -} - -inline Result -ClientImpl::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) { - const auto &boundary = detail::make_multipart_data_boundary(); - const auto &content_type = - detail::serialize_multipart_formdata_get_content_type(boundary); - return send_with_content_provider( - "PUT", path, headers, nullptr, 0, nullptr, - get_multipart_content_provider(boundary, items, provider_items), - content_type); -} -inline Result ClientImpl::Patch(const std::string &path) { - return Patch(path, std::string(), std::string()); -} - -inline Result ClientImpl::Patch(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return Patch(path, Headers(), body, content_length, content_type); + return Patch(path, headers, body, content_type, progress); } inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, const char *body, size_t content_length, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return send_with_content_provider("PATCH", path, headers, body, content_length, nullptr, nullptr, - content_type); -} - -inline Result ClientImpl::Patch(const std::string &path, - const std::string &body, - const std::string &content_type) { - return Patch(path, Headers(), body, content_type); + content_type, progress); } inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, const std::string &body, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return send_with_content_provider("PATCH", path, headers, body.data(), - body.size(), nullptr, nullptr, - content_type); -} - -inline Result ClientImpl::Patch(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return Patch(path, Headers(), content_length, std::move(content_provider), - content_type); -} - -inline Result ClientImpl::Patch(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return Patch(path, Headers(), std::move(content_provider), content_type); + body.size(), nullptr, nullptr, content_type, + progress); } inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return send_with_content_provider("PATCH", path, headers, nullptr, content_length, std::move(content_provider), - nullptr, content_type); + nullptr, content_type, progress); } inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr, - std::move(content_provider), content_type); + std::move(content_provider), content_type, + progress); +} + +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + const FormDataProviderItems &provider_items, + UploadProgress progress) { + const auto &boundary = detail::make_multipart_data_boundary(); + const auto &content_type = + detail::serialize_multipart_formdata_get_content_type(boundary); + return send_with_content_provider( + "PATCH", path, headers, nullptr, 0, nullptr, + get_multipart_content_provider(boundary, items, provider_items), + content_type, progress); +} + +inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + ContentReceiver content_receiver, + DownloadProgress progress) { + Request req; + req.method = "PATCH"; + req.path = path; + req.headers = headers; + req.body = body; + req.content_receiver = + [content_receiver](const char *data, size_t data_length, + size_t /*offset*/, size_t /*total_length*/) { + return content_receiver(data, data_length); + }; + req.download_progress = std::move(progress); + + if (max_timeout_msec_ > 0) { + req.start_time_ = std::chrono::steady_clock::now(); + } + + if (!content_type.empty()) { req.set_header("Content-Type", content_type); } + + return send_(std::move(req)); } -inline Result ClientImpl::Delete(const std::string &path) { - return Delete(path, Headers(), std::string(), std::string()); +inline Result ClientImpl::Delete(const std::string &path, + DownloadProgress progress) { + return Delete(path, Headers(), std::string(), std::string(), progress); } inline Result ClientImpl::Delete(const std::string &path, - const Headers &headers) { - return Delete(path, headers, std::string(), std::string()); + const Headers &headers, + DownloadProgress progress) { + return Delete(path, headers, std::string(), std::string(), progress); } inline Result ClientImpl::Delete(const std::string &path, const char *body, size_t content_length, - const std::string &content_type) { - return Delete(path, Headers(), body, content_length, content_type); + const std::string &content_type, + DownloadProgress progress) { + return Delete(path, Headers(), body, content_length, content_type, progress); +} + +inline Result ClientImpl::Delete(const std::string &path, + const std::string &body, + const std::string &content_type, + DownloadProgress progress) { + return Delete(path, Headers(), body.data(), body.size(), content_type, + progress); +} + +inline Result ClientImpl::Delete(const std::string &path, + const Headers &headers, + const std::string &body, + const std::string &content_type, + DownloadProgress progress) { + return Delete(path, headers, body.data(), body.size(), content_type, + progress); +} + +inline Result ClientImpl::Delete(const std::string &path, const Params ¶ms, + DownloadProgress progress) { + return Delete(path, Headers(), params, progress); +} + +inline Result ClientImpl::Delete(const std::string &path, + const Headers &headers, const Params ¶ms, + DownloadProgress progress) { + auto query = detail::params_to_query_str(params); + return Delete(path, headers, query, "application/x-www-form-urlencoded", + progress); } inline Result ClientImpl::Delete(const std::string &path, const Headers &headers, const char *body, size_t content_length, - const std::string &content_type) { + const std::string &content_type, + DownloadProgress progress) { Request req; req.method = "DELETE"; req.headers = headers; req.path = path; + req.download_progress = std::move(progress); + if (max_timeout_msec_ > 0) { + req.start_time_ = std::chrono::steady_clock::now(); + } if (!content_type.empty()) { req.set_header("Content-Type", content_type); } req.body.assign(body, content_length); @@ -7957,19 +10371,6 @@ inline Result ClientImpl::Delete(const std::string &path, return send_(std::move(req)); } -inline Result ClientImpl::Delete(const std::string &path, - const std::string &body, - const std::string &content_type) { - return Delete(path, Headers(), body.data(), body.size(), content_type); -} - -inline Result ClientImpl::Delete(const std::string &path, - const Headers &headers, - const std::string &body, - const std::string &content_type) { - return Delete(path, headers, body.data(), body.size(), content_type); -} - inline Result ClientImpl::Options(const std::string &path) { return Options(path, Headers()); } @@ -7980,6 +10381,9 @@ inline Result ClientImpl::Options(const std::string &path, req.method = "OPTIONS"; req.headers = headers; req.path = path; + if (max_timeout_msec_ > 0) { + req.start_time_ = std::chrono::steady_clock::now(); + } return send_(std::move(req)); } @@ -7990,8 +10394,8 @@ inline void ClientImpl::stop() { // 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. + // (closing the socket, shutting ssl down) is unsafe because these actions + // are not thread-safe. if (socket_requests_in_flight_ > 0) { shutdown_socket(socket_); @@ -8033,6 +10437,10 @@ inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) { write_timeout_usec_ = usec; } +inline void ClientImpl::set_max_timeout(time_t msec) { + max_timeout_msec_ = msec; +} + inline void ClientImpl::set_basic_auth(const std::string &username, const std::string &password) { basic_auth_username_ = username; @@ -8055,7 +10463,7 @@ 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_path_encode(bool on) { path_encode_ = on; } inline void ClientImpl::set_hostname_addr_map(std::map addr_map) { @@ -8077,6 +10485,8 @@ inline void ClientImpl::set_address_family(int family) { inline void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; } +inline void ClientImpl::set_ipv6_v6only(bool on) { ipv6_v6only_ = on; } + inline void ClientImpl::set_socket_options(SocketOptions socket_options) { socket_options_ = std::move(socket_options); } @@ -8126,13 +10536,11 @@ inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) { inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert, std::size_t size) const { auto mem = BIO_new_mem_buf(ca_cert, static_cast(size)); + auto se = detail::scope_exit([&] { BIO_free_all(mem); }); if (!mem) { return nullptr; } auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr); - if (!inf) { - BIO_free_all(mem); - return nullptr; - } + if (!inf) { return nullptr; } auto cts = X509_STORE_new(); if (cts) { @@ -8146,25 +10554,44 @@ inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert, } sk_X509_INFO_pop_free(inf, X509_INFO_free); - BIO_free_all(mem); return cts; } inline void ClientImpl::enable_server_certificate_verification(bool enabled) { server_certificate_verification_ = enabled; } + +inline void ClientImpl::enable_server_hostname_verification(bool enabled) { + server_hostname_verification_ = enabled; +} + +inline void ClientImpl::set_server_certificate_verifier( + std::function verifier) { + server_certificate_verifier_ = verifier; +} #endif inline void ClientImpl::set_logger(Logger logger) { logger_ = std::move(logger); } +inline void ClientImpl::set_error_logger(ErrorLogger error_logger) { + error_logger_ = std::move(error_logger); +} + /* * SSL Implementation */ #ifdef CPPHTTPLIB_OPENSSL_SUPPORT namespace detail { +inline bool is_ip_address(const std::string &host) { + struct in_addr addr4; + struct in6_addr addr6; + return inet_pton(AF_INET, host.c_str(), &addr4) == 1 || + inet_pton(AF_INET6, host.c_str(), &addr6) == 1; +} + template inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex, U SSL_connect_or_accept, V setup) { @@ -8196,13 +10623,21 @@ inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex, return ssl; } -inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, +inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, socket_t sock, 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); } + if (shutdown_gracefully) { + (void)(sock); + // SSL_shutdown() returns 0 on first call (indicating close_notify alert + // sent) and 1 on subsequent call (indicating close_notify alert received) + if (SSL_shutdown(ssl) == 0) { + // Expected to return 1, but even if it doesn't, we free ssl + SSL_shutdown(ssl); + } + } std::lock_guard guard(ctx_mutex); SSL_free(ssl); @@ -8211,8 +10646,8 @@ inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, template bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl, U ssl_connect_or_accept, - time_t timeout_sec, - time_t timeout_usec) { + time_t timeout_sec, time_t timeout_usec, + int *ssl_error) { auto res = 0; while ((res = ssl_connect_or_accept(ssl)) != 1) { auto err = SSL_get_error(ssl, res); @@ -8225,6 +10660,7 @@ bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl, break; default: break; } + if (ssl_error) { *ssl_error = err; } return false; } return true; @@ -8246,51 +10682,59 @@ inline bool process_server_socket_ssl( } template -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) { +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, + time_t max_timeout_msec, + std::chrono::time_point start_time, T callback) { SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec, - write_timeout_sec, write_timeout_usec); + write_timeout_sec, write_timeout_usec, max_timeout_msec, + start_time); return callback(strm); } -class SSLInit { -public: - SSLInit() { - OPENSSL_init_ssl( - OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); - } -}; - // 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) +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, + time_t max_timeout_msec, + std::chrono::time_point start_time) : 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) { + write_timeout_usec_(write_timeout_usec), + max_timeout_msec_(max_timeout_msec), start_time_(start_time) { SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY); } inline SSLSocketStream::~SSLSocketStream() = default; inline bool SSLSocketStream::is_readable() const { - return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0; + return SSL_pending(ssl_) > 0; +} + +inline bool SSLSocketStream::wait_readable() const { + if (max_timeout_msec_ <= 0) { + return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0; + } + + time_t read_timeout_sec; + time_t read_timeout_usec; + calc_actual_timeout(max_timeout_msec_, duration(), read_timeout_sec_, + read_timeout_usec_, read_timeout_sec, read_timeout_usec); + + return select_read(sock_, read_timeout_sec, read_timeout_usec) > 0; } -inline bool SSLSocketStream::is_writable() const { +inline bool SSLSocketStream::wait_writable() const { return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 && - is_socket_alive(sock_); + is_socket_alive(sock_) && !is_ssl_peer_could_be_closed(ssl_, sock_); } inline ssize_t SSLSocketStream::read(char *ptr, size_t size) { if (SSL_pending(ssl_) > 0) { return SSL_read(ssl_, ptr, static_cast(size)); - } else if (is_readable()) { + } else if (wait_readable()) { auto ret = SSL_read(ssl_, ptr, static_cast(size)); if (ret < 0) { auto err = SSL_get_error(ssl_, ret); @@ -8304,23 +10748,25 @@ inline ssize_t SSLSocketStream::read(char *ptr, size_t size) { #endif if (SSL_pending(ssl_) > 0) { return SSL_read(ssl_, ptr, static_cast(size)); - } else if (is_readable()) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } else if (wait_readable()) { + std::this_thread::sleep_for(std::chrono::microseconds{10}); ret = SSL_read(ssl_, ptr, static_cast(size)); if (ret >= 0) { return ret; } err = SSL_get_error(ssl_, ret); } else { - return -1; + break; } } + assert(ret < 0); } return ret; + } else { + return -1; } - return -1; } inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) { - if (is_writable()) { + if (wait_writable()) { auto handle_size = static_cast( std::min(size, (std::numeric_limits::max)())); @@ -8335,15 +10781,16 @@ inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) { #else while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) { #endif - if (is_writable()) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (wait_writable()) { + std::this_thread::sleep_for(std::chrono::microseconds{10}); ret = SSL_write(ssl_, ptr, static_cast(handle_size)); if (ret >= 0) { return ret; } err = SSL_get_error(ssl_, ret); } else { - return -1; + break; } } + assert(ret < 0); } return ret; } @@ -8362,7 +10809,11 @@ inline void SSLSocketStream::get_local_ip_and_port(std::string &ip, inline socket_t SSLSocketStream::socket() const { return sock_; } -static SSLInit sslinit_; +inline time_t SSLSocketStream::duration() const { + return std::chrono::duration_cast( + std::chrono::steady_clock::now() - start_time_) + .count(); +} } // namespace detail @@ -8378,9 +10829,8 @@ inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path, SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); - SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION); + SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION); - // add default password callback before opening encrypted private key if (private_key_password != nullptr && (private_key_password[0] != '\0')) { SSL_CTX_set_default_passwd_cb_userdata( ctx_, @@ -8389,13 +10839,28 @@ inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path, if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 || SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) != - 1) { + 1 || + SSL_CTX_check_private_key(ctx_) != 1) { + last_ssl_error_ = static_cast(ERR_get_error()); 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); + // Set client CA list to be sent to clients during TLS handshake + if (client_ca_cert_file_path) { + auto ca_list = SSL_load_client_CA_file(client_ca_cert_file_path); + if (ca_list != nullptr) { + SSL_CTX_set_client_CA_list(ctx_, ca_list); + } else { + // Failed to load client CA list, but we continue since + // SSL_CTX_load_verify_locations already succeeded and + // certificate verification will still work + last_ssl_error_ = static_cast(ERR_get_error()); + } + } + SSL_CTX_set_verify( ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); } @@ -8411,7 +10876,7 @@ inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key, SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); - SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION); + SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION); if (SSL_CTX_use_certificate(ctx_, cert) != 1 || SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) { @@ -8420,6 +10885,15 @@ inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key, } else if (client_ca_cert_store) { SSL_CTX_set_cert_store(ctx_, client_ca_cert_store); + // Extract CA names from the store and set them as the client CA list + auto ca_list = extract_ca_names_from_x509_store(client_ca_cert_store); + if (ca_list) { + SSL_CTX_set_client_CA_list(ctx_, ca_list); + } else { + // Failed to extract CA names, record the error + last_ssl_error_ = static_cast(ERR_get_error()); + } + SSL_CTX_set_verify( ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); } @@ -8445,31 +10919,54 @@ inline bool SSLServer::is_valid() const { return ctx_; } inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; } +inline void SSLServer::update_certs(X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store) { + + std::lock_guard guard(ctx_mutex_); + + SSL_CTX_use_certificate(ctx_, cert); + SSL_CTX_use_PrivateKey(ctx_, private_key); + + if (client_ca_cert_store != nullptr) { + SSL_CTX_set_cert_store(ctx_, client_ca_cert_store); + } +} + inline bool SSLServer::process_and_close_socket(socket_t sock) { auto ssl = detail::ssl_new( sock, ctx_, ctx_mutex_, [&](SSL *ssl2) { return detail::ssl_connect_or_accept_nonblocking( - sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_); + sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_, + &last_ssl_error_); }, [](SSL * /*ssl2*/) { return true; }); auto ret = false; if (ssl) { + std::string remote_addr; + int remote_port = 0; + detail::get_remote_ip_and_port(sock, remote_addr, remote_port); + + std::string local_addr; + int local_port = 0; + detail::get_local_ip_and_port(sock, local_addr, local_port); + 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, + [&](Stream &strm, bool close_connection, bool &connection_closed) { + return process_request(strm, remote_addr, remote_port, local_addr, + local_port, 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::ssl_delete(ctx_mutex_, ssl, sock, shutdown_gracefully); } detail::shutdown_socket(sock); @@ -8477,6 +10974,44 @@ inline bool SSLServer::process_and_close_socket(socket_t sock) { return ret; } +inline STACK_OF(X509_NAME) * SSLServer::extract_ca_names_from_x509_store( + X509_STORE *store) { + if (!store) { return nullptr; } + + auto ca_list = sk_X509_NAME_new_null(); + if (!ca_list) { return nullptr; } + + // Get all objects from the store + auto objs = X509_STORE_get0_objects(store); + if (!objs) { + sk_X509_NAME_free(ca_list); + return nullptr; + } + + // Iterate through objects and extract certificate subject names + for (int i = 0; i < sk_X509_OBJECT_num(objs); i++) { + auto obj = sk_X509_OBJECT_value(objs, i); + if (X509_OBJECT_get_type(obj) == X509_LU_X509) { + auto cert = X509_OBJECT_get0_X509(obj); + if (cert) { + auto subject = X509_get_subject_name(cert); + if (subject) { + auto name_dup = X509_NAME_dup(subject); + if (name_dup) { sk_X509_NAME_push(ca_list, name_dup); } + } + } + } + } + + // If no names were extracted, free the list and return nullptr + if (sk_X509_NAME_num(ca_list) == 0) { + sk_X509_NAME_free(ca_list); + return nullptr; + } + + return ca_list; +} + // SSL HTTP client implementation inline SSLClient::SSLClient(const std::string &host) : SSLClient(host, 443, std::string(), std::string()) {} @@ -8486,20 +11021,30 @@ inline SSLClient::SSLClient(const std::string &host, int port) inline SSLClient::SSLClient(const std::string &host, int port, const std::string &client_cert_path, - const std::string &client_key_path) + const std::string &client_key_path, + const std::string &private_key_password) : ClientImpl(host, port, client_cert_path, client_key_path) { ctx_ = SSL_CTX_new(TLS_client_method()); + SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION); + detail::split(&host_[0], &host_[host_.size()], '.', [&](const char *b, const char *e) { host_components_.emplace_back(b, e); }); if (!client_cert_path.empty() && !client_key_path.empty()) { + if (!private_key_password.empty()) { + SSL_CTX_set_default_passwd_cb_userdata( + ctx_, reinterpret_cast( + const_cast(private_key_password.c_str()))); + } + 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) { + last_openssl_error_ = ERR_get_error(); SSL_CTX_free(ctx_); ctx_ = nullptr; } @@ -8507,7 +11052,8 @@ inline SSLClient::SSLClient(const std::string &host, int port, } inline SSLClient::SSLClient(const std::string &host, int port, - X509 *client_cert, EVP_PKEY *client_key) + X509 *client_cert, EVP_PKEY *client_key, + const std::string &private_key_password) : ClientImpl(host, port) { ctx_ = SSL_CTX_new(TLS_client_method()); @@ -8517,8 +11063,15 @@ inline SSLClient::SSLClient(const std::string &host, int port, }); if (client_cert != nullptr && client_key != nullptr) { + if (!private_key_password.empty()) { + SSL_CTX_set_default_passwd_cb_userdata( + ctx_, reinterpret_cast( + const_cast(private_key_password.c_str()))); + } + if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 || SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) { + last_openssl_error_ = ERR_get_error(); SSL_CTX_free(ctx_); ctx_ = nullptr; } @@ -8539,8 +11092,10 @@ 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` + // Free memory allocated for old cert and use new store + // `ca_cert_store` SSL_CTX_set_cert_store(ctx_, ca_cert_store); + ca_cert_store_ = ca_cert_store; } } else { X509_STORE_free(ca_cert_store); @@ -8567,17 +11122,24 @@ inline bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) { return 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) { +// Assumes that socket_mutex_ is locked and that there are no requests in +// flight +inline bool SSLClient::connect_with_proxy( + Socket &socket, + std::chrono::time_point start_time, + Response &res, bool &success, Error &error) { success = true; Response proxy_res; if (!detail::process_client_socket( socket.sock, read_timeout_sec_, read_timeout_usec_, - write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) { + write_timeout_sec_, write_timeout_usec_, max_timeout_msec_, + start_time, [&](Stream &strm) { Request req2; req2.method = "CONNECT"; req2.path = host_and_port_; + if (max_timeout_msec_ > 0) { + req2.start_time_ = std::chrono::steady_clock::now(); + } return process_request(strm, req2, proxy_res, false, error); })) { // Thread-safe to close everything because we are assuming there are no @@ -8594,10 +11156,24 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res, !proxy_digest_auth_password_.empty()) { std::map auth; if (detail::parse_www_authenticate(proxy_res, auth, true)) { + // Close the current socket and create a new one for the authenticated + // request + shutdown_ssl(socket, true); + shutdown_socket(socket); + close_socket(socket); + + // Create a new socket for the authenticated CONNECT request + if (!create_and_connect_socket(socket, error)) { + success = false; + output_error_log(error, nullptr); + return false; + } + proxy_res = Response(); if (!detail::process_client_socket( socket.sock, read_timeout_sec_, read_timeout_usec_, - write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) { + write_timeout_sec_, write_timeout_usec_, max_timeout_msec_, + start_time, [&](Stream &strm) { Request req3; req3.method = "CONNECT"; req3.path = host_and_port_; @@ -8605,6 +11181,9 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res, req3, auth, 1, detail::random_string(10), proxy_digest_auth_username_, proxy_digest_auth_password_, true)); + if (max_timeout_msec_ > 0) { + req3.start_time_ = std::chrono::steady_clock::now(); + } return process_request(strm, req3, proxy_res, false, error); })) { // Thread-safe to close everything because we are assuming there are @@ -8624,6 +11203,7 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res, // as the response of the request if (proxy_res.status != StatusCode::OK_200) { error = Error::ProxyConnection; + output_error_log(error, nullptr); res = std::move(proxy_res); // Thread-safe to close everything because we are assuming there are // no requests in flight @@ -8644,11 +11224,13 @@ inline bool SSLClient::load_certs() { if (!ca_cert_file_path_.empty()) { if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(), nullptr)) { + last_openssl_error_ = ERR_get_error(); ret = false; } } else if (!ca_cert_dir_path_.empty()) { if (!SSL_CTX_load_verify_locations(ctx_, nullptr, ca_cert_dir_path_.c_str())) { + last_openssl_error_ = ERR_get_error(); ret = false; } } else { @@ -8656,10 +11238,8 @@ inline bool SSLClient::load_certs() { #ifdef _WIN32 loaded = detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_)); -#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__) -#if TARGET_OS_OSX +#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && TARGET_OS_MAC loaded = detail::load_system_certs_on_macos(SSL_CTX_get_cert_store(ctx_)); -#endif // TARGET_OS_OSX #endif // _WIN32 if (!loaded) { SSL_CTX_set_default_verify_paths(ctx_); } } @@ -8675,6 +11255,7 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) { if (server_certificate_verification_) { if (!load_certs()) { error = Error::SSLLoadingCerts; + output_error_log(error, nullptr); return false; } SSL_set_verify(ssl2, SSL_VERIFY_NONE, nullptr); @@ -8682,42 +11263,72 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) { if (!detail::ssl_connect_or_accept_nonblocking( socket.sock, ssl2, SSL_connect, connection_timeout_sec_, - connection_timeout_usec_)) { + connection_timeout_usec_, &last_ssl_error_)) { error = Error::SSLConnection; + output_error_log(error, nullptr); return false; } if (server_certificate_verification_) { - verify_result_ = SSL_get_verify_result(ssl2); + auto verification_status = SSLVerifierResponse::NoDecisionMade; - if (verify_result_ != X509_V_OK) { - error = Error::SSLServerVerification; - return false; + if (server_certificate_verifier_) { + verification_status = server_certificate_verifier_(ssl2); } - auto server_cert = SSL_get1_peer_certificate(ssl2); - - if (server_cert == nullptr) { + if (verification_status == SSLVerifierResponse::CertificateRejected) { + last_openssl_error_ = ERR_get_error(); error = Error::SSLServerVerification; + output_error_log(error, nullptr); return false; } - if (!verify_host(server_cert)) { - X509_free(server_cert); - error = Error::SSLServerVerification; - return false; + if (verification_status == SSLVerifierResponse::NoDecisionMade) { + verify_result_ = SSL_get_verify_result(ssl2); + + if (verify_result_ != X509_V_OK) { + last_openssl_error_ = static_cast(verify_result_); + error = Error::SSLServerVerification; + output_error_log(error, nullptr); + return false; + } + + auto server_cert = SSL_get1_peer_certificate(ssl2); + auto se = detail::scope_exit([&] { X509_free(server_cert); }); + + if (server_cert == nullptr) { + last_openssl_error_ = ERR_get_error(); + error = Error::SSLServerVerification; + output_error_log(error, nullptr); + return false; + } + + if (server_hostname_verification_) { + if (!verify_host(server_cert)) { + last_openssl_error_ = X509_V_ERR_HOSTNAME_MISMATCH; + error = Error::SSLServerHostnameVerification; + output_error_log(error, nullptr); + return false; + } + } } - X509_free(server_cert); } return true; }, [&](SSL *ssl2) { - // NOTE: With -Wold-style-cast, this can produce a warning, since - // SSL_set_tlsext_host_name is a macro (in OpenSSL), which contains - // an old style cast. Short of doing compiler specific pragma's - // here, we can't get rid of this warning. :'( - SSL_set_tlsext_host_name(ssl2, host_.c_str()); + // Set SNI only if host is not IP address + if (!detail::is_ip_address(host_)) { +#if defined(OPENSSL_IS_BORINGSSL) + SSL_set_tlsext_host_name(ssl2, host_.c_str()); +#else + // NOTE: Direct call instead of using the OpenSSL macro to suppress + // -Wold-style-cast warning + SSL_ctrl(ssl2, SSL_CTRL_SET_TLSEXT_HOSTNAME, + TLSEXT_NAMETYPE_host_name, + static_cast(const_cast(host_.c_str()))); +#endif + } return true; }); @@ -8726,6 +11337,11 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) { return true; } + if (ctx_ == nullptr) { + error = Error::SSLConnection; + last_openssl_error_ = ERR_get_error(); + } + shutdown_socket(socket); close_socket(socket); return false; @@ -8742,19 +11358,22 @@ inline void SSLClient::shutdown_ssl_impl(Socket &socket, return; } if (socket.ssl) { - detail::ssl_delete(ctx_mutex_, socket.ssl, shutdown_gracefully); + detail::ssl_delete(ctx_mutex_, socket.ssl, socket.sock, + shutdown_gracefully); socket.ssl = nullptr; } assert(socket.ssl == nullptr); } -inline bool -SSLClient::process_socket(const Socket &socket, - std::function callback) { +inline bool SSLClient::process_socket( + const Socket &socket, + std::chrono::time_point start_time, + std::function 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)); + write_timeout_sec_, write_timeout_usec_, max_timeout_msec_, start_time, + std::move(callback)); } inline bool SSLClient::is_ssl() const { return true; } @@ -8791,8 +11410,8 @@ SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const { auto type = GEN_DNS; - struct in6_addr addr6 {}; - struct in_addr addr {}; + struct in6_addr addr6 = {}; + struct in_addr addr = {}; size_t addr_len = 0; #ifndef __MINGW32__ @@ -8816,21 +11435,22 @@ SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const { 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 = - reinterpret_cast(ASN1_STRING_get0_data(val->d.ia5)); - auto name_len = static_cast(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_matched = true; - } - break; + if (!val || val->type != type) { continue; } + + auto name = + reinterpret_cast(ASN1_STRING_get0_data(val->d.ia5)); + if (name == nullptr) { continue; } + + auto name_len = static_cast(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_matched = true; } + break; } } @@ -8894,8 +11514,8 @@ inline Client::Client(const std::string &scheme_host_port) inline Client::Client(const std::string &scheme_host_port, const std::string &client_cert_path, const std::string &client_key_path) { - const Regex re( - R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)"); + const static Regex re( + R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)"); Match m; if (RegexMatch(scheme_host_port, m, re)) { @@ -8932,10 +11552,12 @@ inline Client::Client(const std::string &scheme_host_port, client_key_path); } } else { + // NOTE: Update TEST(UniversalClientImplTest, Ipv6LiteralAddress) + // if port param below changes. cli_ = detail::make_unique(scheme_host_port, 80, client_cert_path, client_key_path); } -} +} // namespace detail inline Client::Client(const std::string &host, int port) : cli_(detail::make_unique(host, port)) {} @@ -8952,73 +11574,56 @@ inline bool Client::is_valid() const { return cli_ != nullptr && cli_->is_valid(); } -inline Result Client::Get(const std::string &path) { return cli_->Get(path); } -inline Result Client::Get(const std::string &path, const Headers &headers) { - return cli_->Get(path, headers); -} -inline Result Client::Get(const std::string &path, Progress progress) { +inline Result Client::Get(const std::string &path, DownloadProgress progress) { return cli_->Get(path, std::move(progress)); } inline Result Client::Get(const std::string &path, const Headers &headers, - Progress progress) { + DownloadProgress progress) { return cli_->Get(path, headers, std::move(progress)); } inline Result Client::Get(const std::string &path, - ContentReceiver content_receiver) { - return cli_->Get(path, std::move(content_receiver)); -} -inline Result Client::Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver) { - return cli_->Get(path, headers, std::move(content_receiver)); -} -inline Result Client::Get(const std::string &path, - ContentReceiver content_receiver, Progress progress) { + ContentReceiver content_receiver, + DownloadProgress progress) { return cli_->Get(path, std::move(content_receiver), std::move(progress)); } inline Result Client::Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver, Progress progress) { + ContentReceiver content_receiver, + DownloadProgress progress) { return cli_->Get(path, headers, std::move(content_receiver), std::move(progress)); } inline Result Client::Get(const std::string &path, ResponseHandler response_handler, - ContentReceiver content_receiver) { - return cli_->Get(path, std::move(response_handler), - std::move(content_receiver)); -} -inline Result Client::Get(const std::string &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 std::string &path, - ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress) { + ContentReceiver content_receiver, + DownloadProgress progress) { return cli_->Get(path, std::move(response_handler), std::move(content_receiver), std::move(progress)); } inline Result Client::Get(const std::string &path, const Headers &headers, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress) { + ContentReceiver content_receiver, + DownloadProgress progress) { return cli_->Get(path, headers, std::move(response_handler), std::move(content_receiver), std::move(progress)); } inline Result Client::Get(const std::string &path, const Params ¶ms, - const Headers &headers, Progress progress) { - return cli_->Get(path, params, headers, progress); + const Headers &headers, DownloadProgress progress) { + return cli_->Get(path, params, headers, std::move(progress)); } inline Result Client::Get(const std::string &path, const Params ¶ms, const Headers &headers, - ContentReceiver content_receiver, Progress progress) { - return cli_->Get(path, params, headers, content_receiver, progress); + ContentReceiver content_receiver, + DownloadProgress progress) { + return cli_->Get(path, params, headers, std::move(content_receiver), + std::move(progress)); } inline Result Client::Get(const std::string &path, const Params ¶ms, const Headers &headers, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress) { - return cli_->Get(path, params, headers, response_handler, content_receiver, - progress); + ContentReceiver content_receiver, + DownloadProgress progress) { + return cli_->Get(path, params, headers, std::move(response_handler), + std::move(content_receiver), std::move(progress)); } inline Result Client::Head(const std::string &path) { return cli_->Head(path); } @@ -9032,45 +11637,55 @@ inline Result Client::Post(const std::string &path, const Headers &headers) { } inline Result Client::Post(const std::string &path, const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Post(path, body, content_length, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Post(path, body, content_length, content_type, progress); } inline Result Client::Post(const std::string &path, const Headers &headers, const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Post(path, headers, body, content_length, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Post(path, headers, body, content_length, content_type, + progress); } inline Result Client::Post(const std::string &path, const std::string &body, - const std::string &content_type) { - return cli_->Post(path, body, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Post(path, body, content_type, progress); } inline Result Client::Post(const std::string &path, const Headers &headers, const std::string &body, - const std::string &content_type) { - return cli_->Post(path, headers, body, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Post(path, headers, body, content_type, progress); } inline Result Client::Post(const std::string &path, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return cli_->Post(path, content_length, std::move(content_provider), - content_type); + content_type, progress); } inline Result Client::Post(const std::string &path, ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Post(path, std::move(content_provider), content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Post(path, std::move(content_provider), content_type, progress); } inline Result Client::Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return cli_->Post(path, headers, content_length, std::move(content_provider), - content_type); + content_type, progress); } inline Result Client::Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Post(path, headers, std::move(content_provider), content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Post(path, headers, std::move(content_provider), content_type, + progress); } inline Result Client::Post(const std::string &path, const Params ¶ms) { return cli_->Post(path, params); @@ -9080,66 +11695,90 @@ inline Result Client::Post(const std::string &path, const Headers &headers, return cli_->Post(path, headers, params); } inline Result Client::Post(const std::string &path, - const MultipartFormDataItems &items) { - return cli_->Post(path, items); + const UploadFormDataItems &items, + UploadProgress progress) { + return cli_->Post(path, items, progress); +} +inline Result Client::Post(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + UploadProgress progress) { + return cli_->Post(path, headers, items, progress); } inline Result Client::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items) { - return cli_->Post(path, headers, items); + const UploadFormDataItems &items, + const std::string &boundary, + UploadProgress progress) { + return cli_->Post(path, headers, items, boundary, progress); } inline Result Client::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string &boundary) { - return cli_->Post(path, headers, items, boundary); + const UploadFormDataItems &items, + const FormDataProviderItems &provider_items, + UploadProgress progress) { + return cli_->Post(path, headers, items, provider_items, progress); } -inline Result -Client::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) { - return cli_->Post(path, headers, items, provider_items); +inline Result Client::Post(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + ContentReceiver content_receiver, + DownloadProgress progress) { + return cli_->Post(path, headers, body, content_type, content_receiver, + progress); } + inline Result Client::Put(const std::string &path) { return cli_->Put(path); } +inline Result Client::Put(const std::string &path, const Headers &headers) { + return cli_->Put(path, headers); +} inline Result Client::Put(const std::string &path, const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Put(path, body, content_length, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Put(path, body, content_length, content_type, progress); } inline Result Client::Put(const std::string &path, const Headers &headers, const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Put(path, headers, body, content_length, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Put(path, headers, body, content_length, content_type, progress); } inline Result Client::Put(const std::string &path, const std::string &body, - const std::string &content_type) { - return cli_->Put(path, body, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Put(path, body, content_type, progress); } inline Result Client::Put(const std::string &path, const Headers &headers, const std::string &body, - const std::string &content_type) { - return cli_->Put(path, headers, body, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Put(path, headers, body, content_type, progress); } inline Result Client::Put(const std::string &path, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return cli_->Put(path, content_length, std::move(content_provider), - content_type); + content_type, progress); } inline Result Client::Put(const std::string &path, ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Put(path, std::move(content_provider), content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Put(path, std::move(content_provider), content_type, progress); } inline Result Client::Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return cli_->Put(path, headers, content_length, std::move(content_provider), - content_type); + content_type, progress); } inline Result Client::Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Put(path, headers, std::move(content_provider), content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Put(path, headers, std::move(content_provider), content_type, + progress); } inline Result Client::Put(const std::string &path, const Params ¶ms) { return cli_->Put(path, params); @@ -9149,94 +11788,173 @@ inline Result Client::Put(const std::string &path, const Headers &headers, return cli_->Put(path, headers, params); } inline Result Client::Put(const std::string &path, - const MultipartFormDataItems &items) { - return cli_->Put(path, items); + const UploadFormDataItems &items, + UploadProgress progress) { + return cli_->Put(path, items, progress); +} +inline Result Client::Put(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + UploadProgress progress) { + return cli_->Put(path, headers, items, progress); } inline Result Client::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items) { - return cli_->Put(path, headers, items); + const UploadFormDataItems &items, + const std::string &boundary, + UploadProgress progress) { + return cli_->Put(path, headers, items, boundary, progress); } inline Result Client::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string &boundary) { - return cli_->Put(path, headers, items, boundary); + const UploadFormDataItems &items, + const FormDataProviderItems &provider_items, + UploadProgress progress) { + return cli_->Put(path, headers, items, provider_items, progress); } -inline Result -Client::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) { - return cli_->Put(path, headers, items, provider_items); +inline Result Client::Put(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + ContentReceiver content_receiver, + DownloadProgress progress) { + return cli_->Put(path, headers, body, content_type, content_receiver, + progress); } + inline Result Client::Patch(const std::string &path) { return cli_->Patch(path); } +inline Result Client::Patch(const std::string &path, const Headers &headers) { + return cli_->Patch(path, headers); +} inline Result Client::Patch(const std::string &path, const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Patch(path, body, content_length, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Patch(path, body, content_length, content_type, progress); } inline Result Client::Patch(const std::string &path, const Headers &headers, const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Patch(path, headers, body, content_length, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Patch(path, headers, body, content_length, content_type, + progress); } inline Result Client::Patch(const std::string &path, const std::string &body, - const std::string &content_type) { - return cli_->Patch(path, body, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Patch(path, body, content_type, progress); } inline Result Client::Patch(const std::string &path, const Headers &headers, const std::string &body, - const std::string &content_type) { - return cli_->Patch(path, headers, body, content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Patch(path, headers, body, content_type, progress); } inline Result Client::Patch(const std::string &path, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return cli_->Patch(path, content_length, std::move(content_provider), - content_type); + content_type, progress); } inline Result Client::Patch(const std::string &path, ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Patch(path, std::move(content_provider), content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Patch(path, std::move(content_provider), content_type, progress); } inline Result Client::Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, - const std::string &content_type) { + const std::string &content_type, + UploadProgress progress) { return cli_->Patch(path, headers, content_length, std::move(content_provider), - content_type); + content_type, progress); } inline Result Client::Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Patch(path, headers, std::move(content_provider), content_type); + const std::string &content_type, + UploadProgress progress) { + return cli_->Patch(path, headers, std::move(content_provider), content_type, + progress); +} +inline Result Client::Patch(const std::string &path, const Params ¶ms) { + return cli_->Patch(path, params); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + const Params ¶ms) { + return cli_->Patch(path, headers, params); +} +inline Result Client::Patch(const std::string &path, + const UploadFormDataItems &items, + UploadProgress progress) { + return cli_->Patch(path, items, progress); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + UploadProgress progress) { + return cli_->Patch(path, headers, items, progress); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + const std::string &boundary, + UploadProgress progress) { + return cli_->Patch(path, headers, items, boundary, progress); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + const UploadFormDataItems &items, + const FormDataProviderItems &provider_items, + UploadProgress progress) { + return cli_->Patch(path, headers, items, provider_items, progress); +} +inline Result Client::Patch(const std::string &path, const Headers &headers, + const std::string &body, + const std::string &content_type, + ContentReceiver content_receiver, + DownloadProgress progress) { + return cli_->Patch(path, headers, body, content_type, content_receiver, + progress); } -inline Result Client::Delete(const std::string &path) { - return cli_->Delete(path); + +inline Result Client::Delete(const std::string &path, + DownloadProgress progress) { + return cli_->Delete(path, progress); } -inline Result Client::Delete(const std::string &path, const Headers &headers) { - return cli_->Delete(path, headers); +inline Result Client::Delete(const std::string &path, const Headers &headers, + DownloadProgress progress) { + return cli_->Delete(path, headers, progress); } inline Result Client::Delete(const std::string &path, const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Delete(path, body, content_length, content_type); + const std::string &content_type, + DownloadProgress progress) { + return cli_->Delete(path, body, content_length, content_type, progress); } inline Result Client::Delete(const std::string &path, const Headers &headers, const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Delete(path, headers, body, content_length, content_type); + const std::string &content_type, + DownloadProgress progress) { + return cli_->Delete(path, headers, body, content_length, content_type, + progress); } inline Result Client::Delete(const std::string &path, const std::string &body, - const std::string &content_type) { - return cli_->Delete(path, body, content_type); + const std::string &content_type, + DownloadProgress progress) { + return cli_->Delete(path, body, content_type, progress); } inline Result Client::Delete(const std::string &path, const Headers &headers, const std::string &body, - const std::string &content_type) { - return cli_->Delete(path, headers, body, content_type); + const std::string &content_type, + DownloadProgress progress) { + return cli_->Delete(path, headers, body, content_type, progress); } +inline Result Client::Delete(const std::string &path, const Params ¶ms, + DownloadProgress progress) { + return cli_->Delete(path, params, progress); +} +inline Result Client::Delete(const std::string &path, const Headers &headers, + const Params ¶ms, DownloadProgress progress) { + return cli_->Delete(path, headers, params, progress); +} + inline Result Client::Options(const std::string &path) { return cli_->Options(path); } @@ -9315,7 +12033,12 @@ 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_path_encode(bool on) { cli_->set_path_encode(on); } + +HTTPLIB_DEPRECATED("Use set_path_encode instead") +inline void Client::set_url_encode(bool on) { + cli_->set_path_encode(on); +} inline void Client::set_compress(bool on) { cli_->set_compress(on); } @@ -9346,12 +12069,25 @@ inline void Client::set_proxy_digest_auth(const std::string &username, inline void Client::enable_server_certificate_verification(bool enabled) { cli_->enable_server_certificate_verification(enabled); } + +inline void Client::enable_server_hostname_verification(bool enabled) { + cli_->enable_server_hostname_verification(enabled); +} + +inline void Client::set_server_certificate_verifier( + std::function verifier) { + cli_->set_server_certificate_verifier(verifier); +} #endif inline void Client::set_logger(Logger logger) { cli_->set_logger(std::move(logger)); } +inline void Client::set_error_logger(ErrorLogger error_logger) { + cli_->set_error_logger(std::move(error_logger)); +} + #ifdef CPPHTTPLIB_OPENSSL_SUPPORT inline void Client::set_ca_cert_path(const std::string &ca_cert_file_path, const std::string &ca_cert_dir_path) { @@ -9391,4 +12127,4 @@ inline SSL_CTX *Client::ssl_context() const { #undef poll #endif -#endif // CPPHTTPLIB_HTTPLIB_H +#endif // CPPHTTPLIB_HTTPLIB_H \ No newline at end of file diff --git a/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp b/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp index bfdc6ca20..84b50c647 100644 --- a/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +++ b/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp @@ -1489,7 +1489,7 @@ typedef enum PGAlterTableType { PG_AT_SetIdentity, /* SET identity column options */ AT_DropIdentity, /* DROP IDENTITY */ PG_AT_SetPartitionedBy, /* SET PARTITIONED BY */ - PG_AT_SetSortedBy /* SET SORTED BY */ + PG_AT_SetSortedBy, /* SET SORTED BY */ } PGAlterTableType; typedef struct PGAlterTableCmd /* one subcommand of an ALTER TABLE */ @@ -1499,7 +1499,8 @@ typedef struct PGAlterTableCmd /* one subcommand of an ALTER TABLE */ char *name; /* column, constraint, or trigger to act on, * or tablespace */ PGNode *def; /* definition of new column, index, * constraint, or parent table */ - PGList *def_list; /* e.g. expression list for partitioned by */ + PGList *def_list; /* e.g. expression list for partitioned by or sorted by */ + PGList *options; /* set table options e.g. SET ('foo'='bar'); RESET ('foo'='bar') */ PGDropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */ bool missing_ok; /* skip error if missing? */ } PGAlterTableCmd; @@ -1616,6 +1617,8 @@ typedef struct PGCreateStmt { PGTypeName *ofTypename; /* OF typename */ PGList *constraints; /* constraints (list of PGConstraint nodes) */ PGList *options; /* options from WITH clause */ + PGList *partition_list; /* e.g. expression list for partitioned by */ + PGList *sort_list; /* e.g. expression list for sort by */ PGOnCommitAction oncommit; /* what do we do at COMMIT? */ char *tablespacename; /* table space to use, or NULL */ PGOnCreateConflict onconflict; /* what to do on create conflict */ @@ -1982,10 +1985,10 @@ typedef struct PGExplainStmt { */ 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 */ + 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; diff --git a/src/duckdb/third_party/libpg_query/include/nodes/primnodes.hpp b/src/duckdb/third_party/libpg_query/include/nodes/primnodes.hpp index cf7928f6e..5b59b9d36 100644 --- a/src/duckdb/third_party/libpg_query/include/nodes/primnodes.hpp +++ b/src/duckdb/third_party/libpg_query/include/nodes/primnodes.hpp @@ -116,6 +116,8 @@ typedef struct PGIntoClause { PGRangeVar *rel; /* target relation name */ PGList *colNames; /* column names to assign, or NIL */ PGList *options; /* options from WITH clause */ + PGList *partition_list; /* e.g. expression list for partitioned by */ + PGList *sort_list; /* e.g. expression list for sort by */ PGOnCommitAction onCommit; /* what do we do at COMMIT? */ char *tableSpaceName; /* table space to use, or NULL */ PGNode *viewQuery; /* materialized view's SELECT query */ diff --git a/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp b/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp index f222526b5..ab18214bb 100644 --- a/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +++ b/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp @@ -1647,16 +1647,16 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 889 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 77384 +#define YYLAST 78071 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 538 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 510 +#define YYNNTS 512 /* YYNRULES -- Number of rules. */ -#define YYNRULES 2257 +#define YYNRULES 2267 /* YYNRULES -- Number of states. */ -#define YYNSTATES 3815 +#define YYNSTATES 3841 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 @@ -1782,309 +1782,310 @@ static const yytype_uint16 yyprhs[] = 972, 975, 978, 981, 985, 989, 993, 995, 999, 1001, 1002, 1004, 1007, 1010, 1017, 1026, 1032, 1040, 1041, 1044, 1047, 1051, 1055, 1058, 1061, 1064, 1066, 1068, 1069, 1072, - 1075, 1076, 1079, 1089, 1102, 1114, 1115, 1118, 1120, 1122, - 1124, 1126, 1128, 1130, 1134, 1135, 1137, 1140, 1142, 1144, - 1147, 1150, 1154, 1156, 1158, 1161, 1164, 1166, 1169, 1173, - 1179, 1183, 1186, 1192, 1194, 1196, 1198, 1199, 1205, 1213, - 1219, 1222, 1226, 1228, 1230, 1233, 1236, 1237, 1241, 1246, - 1251, 1252, 1256, 1259, 1260, 1264, 1266, 1268, 1270, 1272, - 1274, 1276, 1278, 1280, 1282, 1284, 1288, 1292, 1294, 1297, - 1300, 1303, 1306, 1309, 1312, 1313, 1317, 1321, 1325, 1326, - 1328, 1331, 1333, 1336, 1339, 1342, 1345, 1348, 1352, 1355, - 1358, 1360, 1364, 1366, 1368, 1370, 1372, 1376, 1378, 1381, - 1382, 1384, 1387, 1388, 1390, 1394, 1395, 1398, 1399, 1403, - 1407, 1409, 1415, 1419, 1421, 1425, 1427, 1430, 1432, 1437, - 1443, 1449, 1456, 1460, 1468, 1473, 1485, 1487, 1491, 1494, - 1497, 1500, 1501, 1505, 1507, 1509, 1512, 1515, 1518, 1521, - 1523, 1524, 1526, 1529, 1536, 1541, 1548, 1553, 1560, 1569, - 1571, 1573, 1575, 1577, 1580, 1582, 1585, 1587, 1590, 1592, - 1594, 1596, 1598, 1602, 1606, 1610, 1614, 1616, 1619, 1622, - 1624, 1628, 1630, 1632, 1634, 1638, 1640, 1642, 1643, 1645, - 1647, 1649, 1659, 1662, 1663, 1667, 1668, 1670, 1671, 1675, - 1679, 1682, 1684, 1691, 1695, 1699, 1702, 1705, 1707, 1708, - 1714, 1717, 1720, 1721, 1729, 1731, 1733, 1735, 1738, 1744, - 1753, 1761, 1767, 1776, 1784, 1789, 1794, 1796, 1800, 1802, - 1804, 1808, 1810, 1814, 1816, 1818, 1821, 1826, 1830, 1832, - 1836, 1839, 1844, 1849, 1858, 1870, 1880, 1888, 1889, 1893, - 1897, 1899, 1901, 1905, 1906, 1908, 1909, 1911, 1912, 1914, - 1915, 1917, 1921, 1924, 1925, 1928, 1929, 1931, 1932, 1934, - 1936, 1938, 1942, 1946, 1948, 1950, 1954, 1958, 1962, 1966, - 1970, 1974, 1979, 1983, 1986, 1988, 1990, 1992, 1996, 1998, - 2002, 2004, 2006, 2008, 2012, 2016, 2020, 2022, 2025, 2030, - 2035, 2038, 2042, 2048, 2054, 2056, 2058, 2062, 2063, 2075, - 2087, 2098, 2111, 2113, 2116, 2122, 2127, 2132, 2137, 2142, - 2150, 2156, 2161, 2169, 2176, 2186, 2196, 2201, 2203, 2205, - 2207, 2209, 2211, 2213, 2215, 2221, 2223, 2225, 2229, 2231, - 2234, 2237, 2240, 2244, 2246, 2250, 2259, 2265, 2266, 2268, - 2271, 2273, 2277, 2279, 2282, 2283, 2286, 2287, 2291, 2295, - 2300, 2305, 2310, 2315, 2319, 2322, 2324, 2326, 2327, 2329, - 2331, 2332, 2335, 2337, 2343, 2345, 2346, 2349, 2352, 2353, - 2355, 2356, 2360, 2366, 2368, 2372, 2377, 2381, 2383, 2385, - 2386, 2389, 2392, 2393, 2396, 2399, 2401, 2403, 2405, 2406, - 2409, 2414, 2420, 2425, 2428, 2432, 2434, 2436, 2438, 2441, - 2444, 2446, 2449, 2453, 2454, 2456, 2457, 2463, 2465, 2470, - 2477, 2480, 2482, 2483, 2488, 2489, 2491, 2493, 2497, 2502, - 2503, 2505, 2507, 2510, 2513, 2516, 2518, 2520, 2523, 2526, - 2528, 2530, 2532, 2534, 2536, 2538, 2542, 2546, 2547, 2549, - 2553, 2555, 2558, 2560, 2562, 2564, 2566, 2568, 2571, 2576, - 2581, 2587, 2589, 2591, 2594, 2595, 2598, 2599, 2601, 2605, - 2607, 2608, 2610, 2613, 2617, 2620, 2625, 2628, 2632, 2635, - 2636, 2638, 2641, 2642, 2647, 2653, 2655, 2658, 2661, 2662, - 2664, 2668, 2670, 2673, 2676, 2681, 2686, 2690, 2694, 2698, - 2702, 2706, 2710, 2714, 2716, 2721, 2726, 2736, 2746, 2750, - 2751, 2754, 2757, 2758, 2764, 2768, 2770, 2772, 2776, 2782, - 2786, 2788, 2791, 2793, 2797, 2803, 2805, 2808, 2812, 2817, - 2823, 2828, 2834, 2839, 2846, 2852, 2857, 2863, 2869, 2875, - 2878, 2883, 2885, 2887, 2888, 2890, 2895, 2901, 2906, 2907, - 2910, 2913, 2916, 2918, 2920, 2922, 2924, 2925, 2930, 2933, - 2935, 2938, 2941, 2946, 2949, 2956, 2959, 2961, 2965, 2970, - 2971, 2974, 2975, 2978, 2979, 2981, 2985, 2989, 2992, 2993, - 2996, 3001, 3003, 3005, 3007, 3008, 3011, 3015, 3021, 3028, - 3031, 3035, 3038, 3044, 3050, 3056, 3060, 3064, 3068, 3073, - 3074, 3076, 3078, 3080, 3082, 3084, 3087, 3092, 3094, 3096, - 3098, 3100, 3103, 3107, 3108, 3110, 3112, 3114, 3116, 3118, - 3121, 3124, 3127, 3130, 3133, 3135, 3139, 3140, 3142, 3144, - 3146, 3148, 3154, 3157, 3159, 3161, 3163, 3165, 3170, 3172, - 3175, 3178, 3180, 3184, 3188, 3191, 3193, 3194, 3200, 3203, - 3209, 3212, 3214, 3218, 3222, 3223, 3225, 3227, 3229, 3231, - 3233, 3235, 3237, 3239, 3241, 3243, 3245, 3247, 3249, 3251, - 3253, 3255, 3257, 3259, 3261, 3263, 3265, 3267, 3269, 3271, - 3273, 3275, 3277, 3279, 3281, 3283, 3285, 3287, 3289, 3291, - 3293, 3295, 3297, 3299, 3301, 3305, 3309, 3313, 3317, 3321, - 3325, 3329, 3330, 3332, 3336, 3340, 3346, 3349, 3352, 3356, - 3360, 3364, 3368, 3372, 3376, 3380, 3384, 3388, 3392, 3396, - 3400, 3404, 3408, 3412, 3415, 3418, 3422, 3426, 3429, 3432, - 3436, 3440, 3446, 3451, 3458, 3462, 3468, 3473, 3480, 3485, - 3492, 3498, 3506, 3510, 3513, 3518, 3522, 3525, 3530, 3534, - 3538, 3542, 3546, 3551, 3555, 3560, 3564, 3569, 3575, 3582, - 3589, 3597, 3604, 3612, 3619, 3627, 3631, 3636, 3641, 3648, - 3650, 3655, 3660, 3666, 3671, 3678, 3680, 3684, 3687, 3690, - 3694, 3698, 3702, 3706, 3710, 3714, 3718, 3722, 3726, 3730, - 3734, 3738, 3742, 3746, 3750, 3753, 3756, 3762, 3769, 3776, - 3784, 3786, 3789, 3791, 3793, 3795, 3798, 3801, 3806, 3810, - 3812, 3814, 3816, 3818, 3821, 3823, 3825, 3827, 3829, 3831, - 3833, 3835, 3838, 3843, 3846, 3850, 3854, 3859, 3863, 3869, - 3876, 3884, 3894, 3902, 3910, 3916, 3918, 3920, 3922, 3928, - 3935, 3942, 3947, 3952, 3957, 3962, 3969, 3975, 3981, 3987, - 3992, 3999, 4004, 4012, 4022, 4028, 4029, 4035, 4040, 4041, - 4043, 4044, 4047, 4048, 4050, 4054, 4058, 4061, 4064, 4065, - 4072, 4074, 4075, 4079, 4080, 4084, 4088, 4092, 4093, 4095, - 4100, 4103, 4106, 4109, 4112, 4115, 4119, 4122, 4125, 4129, - 4130, 4135, 4139, 4141, 4147, 4151, 4153, 4157, 4159, 4162, - 4166, 4168, 4172, 4174, 4177, 4179, 4180, 4182, 4184, 4186, - 4188, 4190, 4192, 4194, 4196, 4198, 4200, 4202, 4204, 4206, - 4208, 4210, 4212, 4214, 4216, 4218, 4220, 4225, 4227, 4232, - 4234, 4239, 4241, 4244, 4246, 4249, 4251, 4254, 4256, 4260, - 4262, 4266, 4268, 4271, 4273, 4277, 4279, 4282, 4284, 4285, - 4287, 4291, 4293, 4297, 4301, 4303, 4307, 4311, 4312, 4314, - 4316, 4318, 4320, 4322, 4324, 4326, 4328, 4330, 4332, 4334, - 4336, 4338, 4340, 4342, 4347, 4351, 4354, 4358, 4359, 4363, - 4367, 4370, 4373, 4375, 4376, 4379, 4382, 4386, 4389, 4391, - 4393, 4397, 4399, 4401, 4407, 4409, 4412, 4417, 4420, 4421, - 4423, 4424, 4426, 4428, 4431, 4435, 4441, 4449, 4457, 4459, - 4460, 4461, 4464, 4465, 4468, 4472, 4476, 4480, 4486, 4494, - 4502, 4503, 4506, 4508, 4509, 4511, 4512, 4514, 4518, 4520, - 4523, 4527, 4530, 4532, 4536, 4541, 4544, 4546, 4550, 4552, - 4556, 4558, 4561, 4563, 4564, 4568, 4570, 4574, 4576, 4579, - 4584, 4587, 4588, 4592, 4594, 4598, 4600, 4603, 4608, 4611, - 4612, 4614, 4618, 4620, 4624, 4626, 4629, 4631, 4635, 4637, - 4639, 4642, 4644, 4646, 4649, 4651, 4653, 4656, 4664, 4667, - 4673, 4677, 4681, 4683, 4685, 4687, 4689, 4691, 4693, 4695, - 4697, 4699, 4701, 4703, 4705, 4707, 4709, 4712, 4715, 4719, - 4723, 4724, 4726, 4728, 4730, 4736, 4740, 4741, 4743, 4745, - 4747, 4749, 4751, 4753, 4758, 4766, 4773, 4776, 4777, 4779, - 4781, 4783, 4785, 4799, 4816, 4818, 4821, 4822, 4824, 4825, - 4827, 4828, 4831, 4832, 4834, 4835, 4842, 4851, 4858, 4867, - 4874, 4883, 4887, 4890, 4892, 4893, 4900, 4907, 4909, 4911, - 4913, 4915, 4917, 4919, 4922, 4924, 4926, 4928, 4930, 4932, - 4937, 4944, 4948, 4951, 4956, 4960, 4966, 4968, 4969, 4971, - 4973, 4974, 4976, 4978, 4980, 4982, 4984, 4986, 4988, 4990, - 4992, 4994, 4996, 4998, 5000, 5002, 5004, 5006, 5008, 5010, - 5012, 5014, 5016, 5018, 5020, 5022, 5024, 5026, 5028, 5030, - 5032, 5034, 5036, 5038, 5040, 5042, 5044, 5046, 5048, 5050, - 5054, 5056, 5058, 5060, 5062, 5064, 5066, 5069, 5071, 5073, - 5076, 5080, 5084, 5088, 5092, 5094, 5098, 5102, 5105, 5109, - 5113, 5115, 5117, 5119, 5123, 5129, 5131, 5133, 5135, 5137, - 5141, 5144, 5149, 5156, 5163, 5164, 5166, 5168, 5170, 5171, - 5174, 5177, 5182, 5189, 5195, 5200, 5207, 5209, 5211, 5213, - 5215, 5217, 5219, 5220, 5222, 5226, 5228, 5229, 5237, 5241, - 5243, 5246, 5250, 5253, 5254, 5257, 5258, 5261, 5266, 5272, - 5281, 5289, 5292, 5296, 5302, 5304, 5305, 5308, 5309, 5311, - 5312, 5315, 5317, 5321, 5325, 5326, 5329, 5333, 5337, 5341, - 5345, 5347, 5349, 5351, 5354, 5358, 5361, 5364, 5367, 5372, - 5375, 5379, 5384, 5388, 5390, 5392, 5394, 5396, 5398, 5400, - 5401, 5403, 5407, 5410, 5420, 5433, 5445, 5458, 5473, 5477, - 5482, 5487, 5488, 5496, 5507, 5517, 5520, 5524, 5525, 5530, - 5532, 5534, 5536, 5538, 5540, 5542, 5544, 5546, 5548, 5550, - 5552, 5554, 5556, 5558, 5560, 5562, 5564, 5566, 5568, 5570, - 5572, 5574, 5576, 5578, 5580, 5582, 5584, 5586, 5588, 5590, - 5592, 5594, 5596, 5598, 5600, 5602, 5604, 5606, 5608, 5610, - 5612, 5614, 5616, 5618, 5620, 5622, 5624, 5626, 5628, 5630, - 5632, 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, 5650, - 5652, 5654, 5656, 5658, 5660, 5662, 5664, 5666, 5668, 5670, - 5672, 5674, 5676, 5678, 5680, 5682, 5684, 5686, 5688, 5690, - 5692, 5694, 5696, 5698, 5700, 5702, 5704, 5706, 5708, 5710, - 5712, 5714, 5716, 5718, 5720, 5722, 5724, 5726, 5728, 5730, - 5732, 5734, 5736, 5738, 5740, 5742, 5744, 5746, 5748, 5750, - 5752, 5754, 5756, 5758, 5760, 5762, 5764, 5766, 5768, 5770, - 5772, 5774, 5776, 5778, 5780, 5782, 5784, 5786, 5788, 5790, - 5792, 5794, 5796, 5798, 5800, 5802, 5804, 5806, 5808, 5810, - 5812, 5814, 5816, 5818, 5820, 5822, 5824, 5826, 5828, 5830, - 5832, 5834, 5836, 5838, 5840, 5842, 5844, 5846, 5848, 5850, - 5852, 5854, 5856, 5858, 5860, 5862, 5864, 5866, 5868, 5870, - 5872, 5874, 5876, 5878, 5880, 5882, 5884, 5886, 5888, 5890, - 5892, 5894, 5896, 5898, 5900, 5902, 5904, 5906, 5908, 5910, - 5912, 5914, 5916, 5918, 5920, 5922, 5924, 5926, 5928, 5930, - 5932, 5934, 5936, 5938, 5940, 5942, 5944, 5946, 5948, 5950, - 5952, 5954, 5956, 5958, 5960, 5962, 5964, 5966, 5968, 5970, - 5972, 5974, 5976, 5978, 5980, 5982, 5984, 5986, 5988, 5990, - 5992, 5994, 5996, 5998, 6000, 6002, 6004, 6006, 6008, 6010, - 6012, 6014, 6016, 6018, 6020, 6022, 6024, 6026, 6028, 6030, - 6032, 6034, 6036, 6038, 6040, 6042, 6044, 6046, 6048, 6050, - 6052, 6054, 6056, 6058, 6060, 6062, 6064, 6066, 6068, 6070, - 6072, 6074, 6076, 6078, 6080, 6082, 6084, 6086, 6088, 6090, - 6092, 6094, 6096, 6098, 6100, 6102, 6104, 6106, 6108, 6110, - 6112, 6114, 6116, 6118, 6120, 6122, 6124, 6126, 6128, 6130, - 6132, 6134, 6136, 6138, 6140, 6142, 6144, 6146, 6148, 6150, - 6152, 6154, 6156, 6158, 6160, 6162, 6164, 6166, 6168, 6170, - 6172, 6174, 6176, 6178, 6180, 6182, 6184, 6186, 6188, 6190, - 6192, 6194, 6196, 6198, 6200, 6202, 6204, 6206, 6208, 6210, - 6212, 6214, 6216, 6218, 6220, 6222, 6224, 6226, 6228, 6230, - 6232, 6234, 6236, 6238, 6240, 6242, 6244, 6246, 6248, 6250, - 6252, 6254, 6256, 6258, 6260, 6262, 6264, 6266, 6268, 6270, - 6272, 6274, 6276, 6278, 6280, 6282, 6284, 6286, 6288, 6290, - 6292, 6294, 6296, 6298, 6300, 6302, 6304, 6306, 6308, 6310, - 6312, 6314, 6316, 6318, 6320, 6322, 6324, 6326, 6328, 6330, - 6332, 6334, 6336, 6338, 6340, 6342, 6344, 6346, 6348, 6350, - 6352, 6354, 6356, 6358, 6360, 6362, 6364, 6366, 6368, 6370, - 6372, 6374, 6376, 6378, 6380, 6382, 6384, 6386, 6388, 6390, - 6392, 6394, 6396, 6398, 6400, 6402, 6404, 6406, 6408, 6410, - 6412, 6414, 6416, 6418, 6420, 6422, 6424, 6426, 6428, 6430, - 6432, 6434, 6436, 6438, 6440, 6442, 6444, 6446, 6448, 6450, - 6452, 6454, 6456, 6458, 6460, 6462, 6464, 6466, 6468, 6470, - 6472, 6474, 6476, 6478, 6480, 6482, 6484, 6486, 6488, 6490, - 6492, 6494, 6496, 6498, 6500, 6502, 6504, 6506, 6508, 6510, - 6512, 6514, 6516, 6518, 6520, 6522, 6524, 6526, 6528, 6530, - 6532, 6534, 6536, 6538, 6540, 6542, 6544, 6546, 6548, 6550, - 6552, 6554, 6556, 6558, 6560, 6562, 6564, 6566, 6568, 6570, - 6572, 6574, 6576, 6578, 6580, 6582, 6584, 6586, 6588, 6590, - 6592, 6594, 6596, 6598, 6600, 6602, 6604, 6606, 6608, 6610, - 6612, 6614, 6616, 6618, 6620, 6622, 6624, 6626, 6628, 6630, - 6632, 6634, 6636, 6638, 6640, 6642, 6644, 6646, 6648, 6650, - 6652, 6654, 6656, 6658, 6660, 6662, 6664, 6666, 6668, 6670, - 6672, 6674, 6676, 6678, 6680, 6682, 6684, 6686, 6688, 6690, - 6692, 6694, 6696, 6698, 6700, 6702, 6704, 6706, 6708, 6710, - 6712, 6714, 6716, 6718, 6720, 6722, 6724, 6726, 6728, 6730, - 6732, 6734, 6736, 6738, 6740, 6742, 6744, 6746, 6748, 6750, - 6752, 6754, 6756, 6758, 6760, 6762, 6764, 6766, 6768, 6770, - 6772, 6774, 6776, 6778, 6780, 6782, 6784, 6786, 6788, 6790, - 6792, 6794, 6796, 6798, 6800, 6802, 6804, 6806 + 1075, 1076, 1079, 1090, 1104, 1117, 1118, 1121, 1123, 1125, + 1127, 1129, 1131, 1133, 1137, 1138, 1140, 1143, 1145, 1147, + 1150, 1153, 1157, 1159, 1161, 1164, 1167, 1169, 1172, 1176, + 1182, 1186, 1189, 1195, 1197, 1199, 1201, 1202, 1208, 1216, + 1222, 1225, 1229, 1231, 1233, 1236, 1239, 1240, 1244, 1249, + 1254, 1255, 1259, 1262, 1263, 1267, 1269, 1271, 1273, 1275, + 1277, 1279, 1281, 1283, 1285, 1287, 1291, 1295, 1297, 1300, + 1303, 1306, 1309, 1310, 1316, 1322, 1325, 1328, 1331, 1332, + 1336, 1340, 1344, 1345, 1347, 1350, 1352, 1355, 1358, 1361, + 1364, 1367, 1371, 1374, 1377, 1379, 1383, 1385, 1387, 1389, + 1391, 1395, 1397, 1400, 1401, 1403, 1406, 1407, 1409, 1413, + 1414, 1417, 1418, 1422, 1426, 1428, 1434, 1438, 1442, 1444, + 1446, 1450, 1452, 1455, 1457, 1462, 1468, 1474, 1481, 1485, + 1493, 1498, 1510, 1512, 1516, 1519, 1522, 1525, 1526, 1530, + 1532, 1534, 1537, 1540, 1543, 1546, 1548, 1549, 1551, 1554, + 1561, 1566, 1573, 1578, 1585, 1594, 1596, 1598, 1600, 1602, + 1605, 1607, 1610, 1612, 1615, 1617, 1619, 1621, 1623, 1627, + 1631, 1635, 1639, 1641, 1644, 1647, 1649, 1653, 1655, 1657, + 1659, 1663, 1665, 1667, 1668, 1670, 1672, 1674, 1684, 1687, + 1688, 1692, 1693, 1695, 1696, 1700, 1704, 1707, 1709, 1716, + 1720, 1724, 1727, 1730, 1732, 1733, 1739, 1742, 1745, 1746, + 1754, 1756, 1758, 1760, 1763, 1769, 1778, 1786, 1792, 1801, + 1809, 1814, 1819, 1821, 1825, 1827, 1829, 1833, 1835, 1839, + 1841, 1843, 1846, 1851, 1855, 1857, 1861, 1864, 1869, 1874, + 1883, 1895, 1905, 1913, 1914, 1918, 1922, 1924, 1926, 1930, + 1931, 1933, 1934, 1936, 1937, 1939, 1940, 1942, 1946, 1949, + 1950, 1953, 1954, 1956, 1957, 1959, 1961, 1963, 1967, 1971, + 1973, 1975, 1979, 1983, 1987, 1991, 1995, 1999, 2004, 2008, + 2011, 2013, 2015, 2017, 2021, 2023, 2027, 2029, 2031, 2033, + 2037, 2041, 2045, 2047, 2050, 2055, 2060, 2063, 2067, 2073, + 2079, 2081, 2083, 2087, 2088, 2100, 2112, 2123, 2136, 2138, + 2141, 2147, 2152, 2157, 2162, 2167, 2175, 2181, 2186, 2194, + 2201, 2211, 2221, 2226, 2228, 2230, 2232, 2234, 2236, 2238, + 2240, 2246, 2248, 2250, 2254, 2256, 2259, 2262, 2265, 2269, + 2271, 2275, 2284, 2290, 2291, 2293, 2296, 2298, 2302, 2304, + 2307, 2308, 2311, 2312, 2316, 2320, 2325, 2330, 2335, 2340, + 2344, 2347, 2349, 2351, 2352, 2354, 2356, 2357, 2360, 2362, + 2368, 2370, 2371, 2374, 2377, 2378, 2380, 2381, 2385, 2391, + 2393, 2397, 2402, 2406, 2408, 2410, 2411, 2414, 2417, 2418, + 2421, 2424, 2426, 2428, 2430, 2431, 2434, 2439, 2445, 2450, + 2453, 2457, 2459, 2461, 2463, 2466, 2469, 2471, 2474, 2478, + 2479, 2481, 2482, 2488, 2490, 2495, 2502, 2505, 2507, 2508, + 2513, 2514, 2516, 2518, 2522, 2527, 2528, 2530, 2532, 2535, + 2538, 2541, 2543, 2545, 2548, 2551, 2553, 2555, 2557, 2559, + 2561, 2563, 2567, 2571, 2572, 2574, 2578, 2580, 2583, 2585, + 2587, 2589, 2591, 2593, 2596, 2601, 2606, 2612, 2614, 2616, + 2619, 2620, 2623, 2624, 2626, 2630, 2632, 2633, 2635, 2638, + 2642, 2645, 2650, 2653, 2657, 2660, 2661, 2663, 2666, 2667, + 2672, 2678, 2680, 2683, 2686, 2687, 2689, 2693, 2695, 2698, + 2701, 2706, 2711, 2715, 2719, 2723, 2727, 2731, 2735, 2739, + 2741, 2746, 2751, 2761, 2771, 2775, 2776, 2779, 2782, 2783, + 2789, 2793, 2795, 2797, 2801, 2807, 2811, 2813, 2816, 2818, + 2822, 2828, 2830, 2833, 2837, 2842, 2848, 2853, 2859, 2864, + 2871, 2877, 2882, 2888, 2894, 2900, 2903, 2908, 2910, 2912, + 2913, 2915, 2920, 2926, 2931, 2932, 2935, 2938, 2941, 2943, + 2945, 2947, 2949, 2950, 2955, 2958, 2960, 2963, 2966, 2971, + 2974, 2981, 2984, 2986, 2990, 2995, 2996, 2999, 3000, 3003, + 3004, 3006, 3010, 3014, 3017, 3018, 3021, 3026, 3028, 3030, + 3032, 3033, 3036, 3040, 3046, 3052, 3059, 3066, 3069, 3072, + 3076, 3080, 3083, 3089, 3095, 3101, 3105, 3109, 3113, 3118, + 3119, 3121, 3123, 3125, 3127, 3129, 3132, 3137, 3139, 3141, + 3143, 3145, 3148, 3152, 3153, 3155, 3157, 3159, 3161, 3163, + 3166, 3169, 3172, 3175, 3178, 3180, 3184, 3185, 3187, 3189, + 3191, 3193, 3199, 3202, 3204, 3206, 3208, 3210, 3215, 3217, + 3220, 3223, 3225, 3229, 3233, 3236, 3238, 3239, 3245, 3248, + 3254, 3257, 3259, 3263, 3267, 3268, 3270, 3272, 3274, 3276, + 3278, 3280, 3282, 3284, 3286, 3288, 3290, 3292, 3294, 3296, + 3298, 3300, 3302, 3304, 3306, 3308, 3310, 3312, 3314, 3316, + 3318, 3320, 3322, 3324, 3326, 3328, 3330, 3332, 3334, 3336, + 3338, 3340, 3342, 3344, 3346, 3350, 3354, 3358, 3362, 3366, + 3370, 3374, 3375, 3377, 3381, 3385, 3391, 3394, 3397, 3401, + 3405, 3409, 3413, 3417, 3421, 3425, 3429, 3433, 3437, 3441, + 3445, 3449, 3453, 3457, 3460, 3463, 3467, 3471, 3474, 3477, + 3481, 3485, 3491, 3496, 3503, 3507, 3513, 3518, 3525, 3530, + 3537, 3543, 3551, 3555, 3558, 3563, 3567, 3570, 3575, 3579, + 3583, 3587, 3591, 3596, 3600, 3605, 3609, 3614, 3620, 3627, + 3634, 3642, 3649, 3657, 3664, 3672, 3676, 3681, 3686, 3693, + 3695, 3700, 3705, 3711, 3716, 3723, 3725, 3729, 3732, 3735, + 3739, 3743, 3747, 3751, 3755, 3759, 3763, 3767, 3771, 3775, + 3779, 3783, 3787, 3791, 3795, 3798, 3801, 3807, 3814, 3821, + 3829, 3831, 3834, 3836, 3838, 3840, 3843, 3846, 3851, 3855, + 3857, 3859, 3861, 3863, 3866, 3868, 3870, 3872, 3874, 3876, + 3878, 3880, 3883, 3888, 3891, 3895, 3899, 3904, 3908, 3914, + 3921, 3929, 3939, 3947, 3955, 3961, 3963, 3965, 3967, 3973, + 3980, 3987, 3992, 3997, 4002, 4007, 4014, 4020, 4026, 4032, + 4037, 4044, 4049, 4057, 4067, 4073, 4074, 4080, 4085, 4086, + 4088, 4089, 4092, 4093, 4095, 4099, 4103, 4106, 4109, 4110, + 4117, 4119, 4120, 4124, 4125, 4129, 4133, 4137, 4138, 4140, + 4145, 4148, 4151, 4154, 4157, 4160, 4164, 4167, 4170, 4174, + 4175, 4180, 4184, 4186, 4192, 4196, 4198, 4202, 4204, 4207, + 4211, 4213, 4217, 4219, 4222, 4224, 4225, 4227, 4229, 4231, + 4233, 4235, 4237, 4239, 4241, 4243, 4245, 4247, 4249, 4251, + 4253, 4255, 4257, 4259, 4261, 4263, 4265, 4270, 4272, 4277, + 4279, 4284, 4286, 4289, 4291, 4294, 4296, 4299, 4301, 4305, + 4307, 4311, 4313, 4316, 4318, 4322, 4324, 4327, 4329, 4330, + 4332, 4336, 4338, 4342, 4346, 4348, 4352, 4356, 4357, 4359, + 4361, 4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, + 4381, 4383, 4385, 4387, 4392, 4396, 4399, 4403, 4404, 4408, + 4412, 4415, 4418, 4420, 4421, 4424, 4427, 4431, 4434, 4436, + 4438, 4442, 4444, 4446, 4452, 4454, 4457, 4462, 4465, 4466, + 4468, 4469, 4471, 4473, 4476, 4480, 4486, 4494, 4502, 4504, + 4505, 4506, 4509, 4510, 4513, 4517, 4521, 4525, 4531, 4539, + 4547, 4548, 4551, 4553, 4554, 4556, 4557, 4559, 4563, 4565, + 4568, 4572, 4575, 4577, 4581, 4586, 4589, 4591, 4595, 4597, + 4601, 4603, 4606, 4608, 4609, 4613, 4615, 4619, 4621, 4624, + 4629, 4632, 4633, 4637, 4639, 4643, 4645, 4648, 4653, 4656, + 4657, 4659, 4663, 4665, 4669, 4671, 4674, 4676, 4680, 4682, + 4684, 4687, 4689, 4691, 4694, 4696, 4698, 4701, 4709, 4712, + 4718, 4722, 4726, 4728, 4730, 4732, 4734, 4736, 4738, 4740, + 4742, 4744, 4746, 4748, 4750, 4752, 4754, 4757, 4760, 4764, + 4768, 4769, 4771, 4773, 4775, 4781, 4785, 4786, 4788, 4790, + 4792, 4794, 4796, 4798, 4803, 4811, 4818, 4821, 4822, 4824, + 4826, 4828, 4830, 4844, 4861, 4863, 4866, 4867, 4869, 4870, + 4872, 4873, 4876, 4877, 4879, 4880, 4887, 4896, 4903, 4912, + 4919, 4928, 4932, 4935, 4937, 4938, 4945, 4952, 4954, 4956, + 4958, 4960, 4962, 4964, 4967, 4969, 4971, 4973, 4975, 4977, + 4982, 4989, 4993, 4996, 5001, 5005, 5011, 5013, 5014, 5016, + 5018, 5019, 5021, 5023, 5025, 5027, 5029, 5031, 5033, 5035, + 5037, 5039, 5041, 5043, 5045, 5047, 5049, 5051, 5053, 5055, + 5057, 5059, 5061, 5063, 5065, 5067, 5069, 5071, 5073, 5075, + 5077, 5079, 5081, 5083, 5085, 5087, 5089, 5091, 5093, 5095, + 5099, 5101, 5103, 5105, 5107, 5109, 5111, 5114, 5116, 5118, + 5121, 5125, 5129, 5133, 5137, 5139, 5143, 5147, 5150, 5154, + 5158, 5160, 5162, 5164, 5168, 5174, 5176, 5178, 5180, 5182, + 5186, 5189, 5194, 5201, 5208, 5209, 5211, 5213, 5215, 5216, + 5219, 5222, 5227, 5234, 5240, 5245, 5252, 5254, 5256, 5258, + 5260, 5262, 5264, 5265, 5267, 5271, 5273, 5274, 5282, 5286, + 5288, 5291, 5295, 5298, 5299, 5302, 5303, 5306, 5311, 5317, + 5326, 5334, 5337, 5341, 5347, 5349, 5350, 5353, 5354, 5356, + 5357, 5360, 5362, 5366, 5370, 5371, 5374, 5378, 5382, 5386, + 5390, 5392, 5394, 5396, 5399, 5403, 5406, 5409, 5412, 5417, + 5420, 5424, 5429, 5433, 5435, 5437, 5439, 5441, 5443, 5445, + 5446, 5448, 5452, 5455, 5465, 5478, 5490, 5503, 5518, 5522, + 5527, 5532, 5533, 5541, 5552, 5562, 5565, 5569, 5570, 5576, + 5578, 5580, 5582, 5584, 5586, 5588, 5590, 5592, 5594, 5596, + 5598, 5600, 5602, 5604, 5606, 5608, 5610, 5612, 5614, 5616, + 5618, 5620, 5622, 5624, 5626, 5628, 5630, 5632, 5634, 5636, + 5638, 5640, 5642, 5644, 5646, 5648, 5650, 5652, 5654, 5656, + 5658, 5660, 5662, 5664, 5666, 5668, 5670, 5672, 5674, 5676, + 5678, 5680, 5682, 5684, 5686, 5688, 5690, 5692, 5694, 5696, + 5698, 5700, 5702, 5704, 5706, 5708, 5710, 5712, 5714, 5716, + 5718, 5720, 5722, 5724, 5726, 5728, 5730, 5732, 5734, 5736, + 5738, 5740, 5742, 5744, 5746, 5748, 5750, 5752, 5754, 5756, + 5758, 5760, 5762, 5764, 5766, 5768, 5770, 5772, 5774, 5776, + 5778, 5780, 5782, 5784, 5786, 5788, 5790, 5792, 5794, 5796, + 5798, 5800, 5802, 5804, 5806, 5808, 5810, 5812, 5814, 5816, + 5818, 5820, 5822, 5824, 5826, 5828, 5830, 5832, 5834, 5836, + 5838, 5840, 5842, 5844, 5846, 5848, 5850, 5852, 5854, 5856, + 5858, 5860, 5862, 5864, 5866, 5868, 5870, 5872, 5874, 5876, + 5878, 5880, 5882, 5884, 5886, 5888, 5890, 5892, 5894, 5896, + 5898, 5900, 5902, 5904, 5906, 5908, 5910, 5912, 5914, 5916, + 5918, 5920, 5922, 5924, 5926, 5928, 5930, 5932, 5934, 5936, + 5938, 5940, 5942, 5944, 5946, 5948, 5950, 5952, 5954, 5956, + 5958, 5960, 5962, 5964, 5966, 5968, 5970, 5972, 5974, 5976, + 5978, 5980, 5982, 5984, 5986, 5988, 5990, 5992, 5994, 5996, + 5998, 6000, 6002, 6004, 6006, 6008, 6010, 6012, 6014, 6016, + 6018, 6020, 6022, 6024, 6026, 6028, 6030, 6032, 6034, 6036, + 6038, 6040, 6042, 6044, 6046, 6048, 6050, 6052, 6054, 6056, + 6058, 6060, 6062, 6064, 6066, 6068, 6070, 6072, 6074, 6076, + 6078, 6080, 6082, 6084, 6086, 6088, 6090, 6092, 6094, 6096, + 6098, 6100, 6102, 6104, 6106, 6108, 6110, 6112, 6114, 6116, + 6118, 6120, 6122, 6124, 6126, 6128, 6130, 6132, 6134, 6136, + 6138, 6140, 6142, 6144, 6146, 6148, 6150, 6152, 6154, 6156, + 6158, 6160, 6162, 6164, 6166, 6168, 6170, 6172, 6174, 6176, + 6178, 6180, 6182, 6184, 6186, 6188, 6190, 6192, 6194, 6196, + 6198, 6200, 6202, 6204, 6206, 6208, 6210, 6212, 6214, 6216, + 6218, 6220, 6222, 6224, 6226, 6228, 6230, 6232, 6234, 6236, + 6238, 6240, 6242, 6244, 6246, 6248, 6250, 6252, 6254, 6256, + 6258, 6260, 6262, 6264, 6266, 6268, 6270, 6272, 6274, 6276, + 6278, 6280, 6282, 6284, 6286, 6288, 6290, 6292, 6294, 6296, + 6298, 6300, 6302, 6304, 6306, 6308, 6310, 6312, 6314, 6316, + 6318, 6320, 6322, 6324, 6326, 6328, 6330, 6332, 6334, 6336, + 6338, 6340, 6342, 6344, 6346, 6348, 6350, 6352, 6354, 6356, + 6358, 6360, 6362, 6364, 6366, 6368, 6370, 6372, 6374, 6376, + 6378, 6380, 6382, 6384, 6386, 6388, 6390, 6392, 6394, 6396, + 6398, 6400, 6402, 6404, 6406, 6408, 6410, 6412, 6414, 6416, + 6418, 6420, 6422, 6424, 6426, 6428, 6430, 6432, 6434, 6436, + 6438, 6440, 6442, 6444, 6446, 6448, 6450, 6452, 6454, 6456, + 6458, 6460, 6462, 6464, 6466, 6468, 6470, 6472, 6474, 6476, + 6478, 6480, 6482, 6484, 6486, 6488, 6490, 6492, 6494, 6496, + 6498, 6500, 6502, 6504, 6506, 6508, 6510, 6512, 6514, 6516, + 6518, 6520, 6522, 6524, 6526, 6528, 6530, 6532, 6534, 6536, + 6538, 6540, 6542, 6544, 6546, 6548, 6550, 6552, 6554, 6556, + 6558, 6560, 6562, 6564, 6566, 6568, 6570, 6572, 6574, 6576, + 6578, 6580, 6582, 6584, 6586, 6588, 6590, 6592, 6594, 6596, + 6598, 6600, 6602, 6604, 6606, 6608, 6610, 6612, 6614, 6616, + 6618, 6620, 6622, 6624, 6626, 6628, 6630, 6632, 6634, 6636, + 6638, 6640, 6642, 6644, 6646, 6648, 6650, 6652, 6654, 6656, + 6658, 6660, 6662, 6664, 6666, 6668, 6670, 6672, 6674, 6676, + 6678, 6680, 6682, 6684, 6686, 6688, 6690, 6692, 6694, 6696, + 6698, 6700, 6702, 6704, 6706, 6708, 6710, 6712, 6714, 6716, + 6718, 6720, 6722, 6724, 6726, 6728, 6730, 6732, 6734, 6736, + 6738, 6740, 6742, 6744, 6746, 6748, 6750, 6752, 6754, 6756, + 6758, 6760, 6762, 6764, 6766, 6768, 6770, 6772, 6774, 6776, + 6778, 6780, 6782, 6784, 6786, 6788, 6790, 6792, 6794, 6796, + 6798, 6800, 6802, 6804, 6806, 6808, 6810, 6812, 6814, 6816, + 6818, 6820, 6822, 6824, 6826, 6828, 6830, 6832, 6834, 6836, + 6838, 6840, 6842, 6844, 6846, 6848, 6850, 6852 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { 539, 0, -1, 540, -1, 540, 531, 541, -1, 541, - -1, 615, -1, 980, -1, 608, -1, 542, -1, 1018, - -1, 1019, -1, 1035, -1, 981, -1, 983, -1, 701, - -1, 1038, -1, 689, -1, 970, -1, 596, -1, 594, - -1, 622, -1, 589, -1, 557, -1, 1014, -1, 1020, - -1, 616, -1, 672, -1, 604, -1, 988, -1, 986, - -1, 987, -1, 973, -1, 568, -1, 1005, -1, 678, - -1, 593, -1, 967, -1, 566, -1, 714, -1, 618, - -1, 603, -1, 700, -1, 621, -1, 1009, -1, 1027, - -1, 999, -1, 1030, -1, 1036, -1, -1, 33, 427, - 809, 554, -1, 33, 427, 194, 154, 809, 554, -1, + -1, 615, -1, 982, -1, 608, -1, 542, -1, 1020, + -1, 1021, -1, 1037, -1, 983, -1, 985, -1, 703, + -1, 1040, -1, 691, -1, 972, -1, 596, -1, 594, + -1, 622, -1, 589, -1, 557, -1, 1016, -1, 1022, + -1, 616, -1, 674, -1, 604, -1, 990, -1, 988, + -1, 989, -1, 975, -1, 568, -1, 1007, -1, 680, + -1, 593, -1, 969, -1, 566, -1, 716, -1, 618, + -1, 603, -1, 702, -1, 621, -1, 1011, -1, 1029, + -1, 1001, -1, 1032, -1, 1038, -1, -1, 33, 427, + 811, 554, -1, 33, 427, 194, 154, 811, 554, -1, 33, 205, 558, 554, -1, 33, 205, 194, 154, 558, 554, -1, 33, 390, 558, 554, -1, 33, 390, 194, 154, 558, 554, -1, 33, 480, 558, 554, -1, 33, 480, 194, 154, 558, 554, -1, 545, -1, 543, 545, - -1, 395, 118, 858, -1, 138, 118, -1, 365, -1, - 365, 610, 611, -1, 395, 612, -1, 395, 178, 671, + -1, 395, 118, 860, -1, 138, 118, -1, 365, -1, + 365, 610, 611, -1, 395, 612, -1, 395, 178, 673, -1, 553, -1, 546, 532, 553, -1, 548, -1, 547, 548, -1, 530, 564, -1, 559, -1, 559, 547, -1, - 549, 649, -1, 549, 650, -1, 27, 550, -1, 27, + 549, 651, -1, 549, 652, -1, 27, 550, -1, 27, 194, 280, 154, 550, -1, 27, 83, 550, -1, 27, 83, 194, 280, 154, 550, -1, 395, 316, 60, 528, - 906, 529, -1, 363, 316, 60, -1, 395, 406, 60, - 528, 743, 529, -1, 363, 406, 60, -1, 33, 567, + 908, 529, -1, 363, 316, 60, -1, 395, 406, 60, + 528, 745, 529, -1, 363, 406, 60, -1, 33, 567, 559, 544, -1, 33, 567, 559, 138, 280, 285, -1, 33, 567, 559, 395, 280, 285, -1, 33, 567, 559, 395, 413, 614, -1, 33, 567, 559, 395, 637, -1, 33, 567, 559, 363, 637, -1, 33, 567, 559, 395, - 416, 559, -1, 33, 567, 559, 27, 178, 671, 41, + 416, 559, -1, 33, 567, 559, 27, 178, 673, 41, 193, 625, -1, 33, 567, 559, 543, -1, 33, 567, 559, 138, 193, -1, 33, 567, 559, 138, 193, 194, - 154, -1, 138, 567, 194, 154, 549, 676, -1, 138, - 567, 549, 676, -1, 33, 567, 559, 556, 451, 821, - 818, 552, -1, 33, 567, 559, 555, -1, 27, 639, - -1, 33, 94, 955, 623, -1, 470, 94, 955, -1, - 138, 94, 194, 154, 955, 676, -1, 138, 94, 955, - 676, -1, 395, 248, -1, 395, 460, -1, 395, 637, - -1, 363, 637, -1, 555, -1, 467, 858, -1, -1, - 633, -1, 395, 633, -1, 27, 633, -1, 138, 647, + 154, -1, 138, 567, 194, 154, 549, 678, -1, 138, + 567, 549, 678, -1, 33, 567, 559, 556, 451, 823, + 820, 552, -1, 33, 567, 559, 555, -1, 27, 639, + -1, 33, 94, 957, 623, -1, 470, 94, 957, -1, + 138, 94, 194, 154, 957, 678, -1, 138, 94, 957, + 678, -1, 395, 248, -1, 395, 460, -1, 395, 637, + -1, 363, 637, -1, 555, -1, 467, 860, -1, -1, + 633, -1, 395, 633, -1, 27, 633, -1, 138, 649, -1, 551, -1, 554, 532, 551, -1, 299, 528, 546, - 529, -1, 395, 108, -1, 395, -1, -1, 112, 955, - -1, 112, 332, 955, -1, 112, 31, -1, 112, 332, - 31, -1, 560, -1, 559, 562, -1, 3, -1, 1041, - -1, 1042, -1, 559, -1, 5, -1, 5, -1, 563, + 529, -1, 395, 108, -1, 395, -1, -1, 112, 957, + -1, 112, 332, 957, -1, 112, 31, -1, 112, 332, + 31, -1, 560, -1, 559, 562, -1, 3, -1, 1043, + -1, 1044, -1, 559, -1, 5, -1, 5, -1, 563, -1, 562, 563, -1, 530, 564, -1, 565, -1, 3, - -1, 1045, -1, 1041, -1, 1047, -1, 33, 379, 955, - 359, 440, 955, -1, 33, 427, 809, 359, 440, 955, - -1, 33, 427, 194, 154, 809, 359, 440, 955, -1, - 33, 390, 558, 359, 440, 955, -1, 33, 390, 194, - 154, 558, 359, 440, 955, -1, 33, 480, 558, 359, - 440, 955, -1, 33, 480, 194, 154, 558, 359, 440, - 955, -1, 33, 205, 558, 359, 440, 955, -1, 33, - 205, 194, 154, 558, 359, 440, 955, -1, 33, 427, - 809, 359, 567, 549, 440, 955, -1, 33, 427, 194, - 154, 809, 359, 567, 549, 440, 955, -1, 33, 427, - 809, 359, 94, 955, 440, 955, -1, 33, 427, 194, - 154, 809, 359, 94, 955, 440, 955, -1, 83, -1, + -1, 1047, -1, 1043, -1, 1049, -1, 33, 379, 957, + 359, 440, 957, -1, 33, 427, 811, 359, 440, 957, + -1, 33, 427, 194, 154, 811, 359, 440, 957, -1, + 33, 390, 558, 359, 440, 957, -1, 33, 390, 194, + 154, 558, 359, 440, 957, -1, 33, 480, 558, 359, + 440, 957, -1, 33, 480, 194, 154, 558, 359, 440, + 957, -1, 33, 205, 558, 359, 440, 957, -1, 33, + 205, 194, 154, 558, 359, 440, 957, -1, 33, 427, + 811, 359, 567, 549, 440, 957, -1, 33, 427, 194, + 154, 811, 359, 567, 549, 440, 957, -1, 33, 427, + 811, 359, 94, 957, 440, 957, -1, 33, 427, 194, + 154, 811, 359, 94, 957, 440, 957, -1, 83, -1, -1, 573, 215, 576, 222, 570, 571, 569, 577, 579, - -1, 714, -1, 309, 580, 472, 714, -1, 528, 584, - 529, 714, -1, 528, 584, 529, 309, 580, 472, 714, + -1, 716, -1, 309, 580, 472, 716, -1, 528, 584, + 529, 716, -1, 528, 584, 529, 309, 580, 472, 716, -1, 118, 473, -1, 558, -1, 558, 41, 559, -1, 60, 271, -1, 60, 327, -1, -1, 528, 587, 529, - 815, -1, 295, 94, 955, -1, -1, 726, -1, -1, - 559, 929, -1, 588, 517, 858, -1, 528, 581, 529, - 517, 858, -1, 300, 361, -1, 300, 195, -1, -1, - 295, 92, 572, 134, 464, 395, 586, 815, -1, 295, - 92, 572, 134, 281, -1, -1, 559, 582, 583, 745, - 746, -1, 870, 582, 583, 745, 746, -1, 528, 858, - 529, 582, 583, 745, 746, -1, 367, 935, -1, -1, + 817, -1, 295, 94, 957, -1, -1, 728, -1, -1, + 559, 931, -1, 588, 517, 860, -1, 528, 581, 529, + 517, 860, -1, 300, 361, -1, 300, 195, -1, -1, + 295, 92, 572, 134, 464, 395, 586, 817, -1, 295, + 92, 572, 134, 281, -1, -1, 559, 582, 583, 747, + 748, -1, 872, 582, 583, 747, 748, -1, 528, 860, + 529, 582, 583, 747, 748, -1, 367, 937, -1, -1, 466, -1, 426, -1, 588, -1, 581, 532, 588, -1, - 81, 962, -1, -1, 962, -1, -1, 574, -1, 584, + 81, 964, -1, -1, 964, -1, -1, 574, -1, 584, 532, 574, -1, 575, -1, 585, 532, 575, -1, 585, -1, 585, 532, -1, 578, -1, 587, 532, 578, -1, - 559, 929, -1, 101, 670, 451, 558, 41, 590, -1, - 101, 670, 451, 194, 280, 154, 558, 41, 590, -1, - 101, 300, 361, 670, 451, 558, 41, 590, -1, 145, - 715, -1, 145, 528, 591, 529, -1, 822, -1, 592, + 559, 931, -1, 101, 672, 451, 558, 41, 590, -1, + 101, 672, 451, 194, 280, 154, 558, 41, 590, -1, + 101, 300, 361, 672, 451, 558, 41, 590, -1, 145, + 717, -1, 145, 528, 591, 529, -1, 824, -1, 592, -1, -1, 561, -1, 592, 532, 561, -1, 329, 559, - -1, 329, 559, 517, 1004, -1, 329, 559, 528, 908, - 529, -1, 101, 670, 390, 558, 595, -1, 101, 670, + -1, 329, 559, 517, 1006, -1, 329, 559, 528, 910, + 529, -1, 101, 672, 390, 558, 595, -1, 101, 672, 390, 194, 280, 154, 558, 595, -1, 101, 300, 361, - 670, 390, 558, 595, -1, 609, -1, -1, 101, 598, + 672, 390, 558, 595, -1, 609, -1, -1, 101, 598, 386, 597, 599, 528, 602, 529, -1, 101, 598, 386, 194, 280, 154, 597, 599, 528, 602, 529, -1, 101, 300, 361, 598, 386, 597, 599, 528, 602, 529, -1, -1, 559, -1, -1, 434, -1, 320, -1, -1, 201, - 3, -1, 858, -1, 565, 600, -1, 601, -1, 602, - 532, 601, -1, 573, 464, 159, 659, -1, 153, 955, - 607, -1, 101, 670, 427, 1040, 41, 153, 955, 607, - 1039, -1, 101, 670, 427, 194, 280, 154, 1040, 41, - 153, 955, 607, 1039, -1, 858, -1, 965, 13, 858, + 3, -1, 860, -1, 565, 600, -1, 601, -1, 602, + 532, 601, -1, 573, 464, 159, 661, -1, 153, 957, + 607, -1, 101, 672, 427, 1042, 41, 153, 957, 607, + 1041, -1, 101, 672, 427, 194, 280, 154, 1042, 41, + 153, 957, 607, 1041, -1, 860, -1, 967, 13, 860, -1, 605, -1, 606, 532, 605, -1, 528, 606, 529, -1, -1, 33, 390, 558, 609, -1, 33, 390, 194, 154, 558, 609, -1, 612, -1, 609, 612, -1, 490, -1, 514, -1, -1, 4, -1, 519, 4, -1, 520, - 4, -1, 614, -1, 41, 825, -1, 61, 611, -1, + 4, -1, 614, -1, 41, 827, -1, 61, 611, -1, 107, -1, 278, 107, -1, 204, 613, 611, -1, 255, 611, -1, 266, 611, -1, 278, 255, -1, 278, 266, - -1, 310, 60, 962, -1, 390, 271, 962, -1, 411, + -1, 310, 60, 964, -1, 390, 271, 964, -1, 411, 610, 611, -1, 365, -1, 365, 610, 611, -1, 60, - -1, -1, 958, -1, 519, 958, -1, 520, 958, -1, + -1, -1, 960, -1, 519, 960, -1, 520, 960, -1, 33, 109, 559, 359, 440, 559, -1, 33, 109, 194, 154, 559, 359, 440, 559, -1, 138, 598, 386, 559, 617, -1, 138, 598, 386, 194, 154, 559, 617, -1, @@ -2092,589 +2093,594 @@ static const yytype_int16 yyrhs[] = -1, 411, 619, 620, -1, 87, 619, -1, 144, 619, -1, 372, 619, -1, 493, -1, 442, -1, -1, 347, 296, -1, 347, 495, -1, -1, 465, 558, -1, 101, - 670, 427, 558, 528, 657, 529, 644, 636, -1, 101, - 670, 427, 194, 280, 154, 558, 528, 657, 529, 644, - 636, -1, 101, 300, 361, 670, 427, 558, 528, 657, - 529, 644, 636, -1, -1, 623, 648, -1, 665, -1, - 1047, -1, 900, -1, 611, -1, 561, -1, 279, -1, - 528, 609, 529, -1, -1, 561, -1, 278, 26, -1, - 366, -1, 64, -1, 395, 285, -1, 395, 118, -1, - 94, 955, 629, -1, 629, -1, 643, -1, 81, 962, - -1, 280, 285, -1, 285, -1, 457, 656, -1, 335, - 229, 656, -1, 75, 528, 858, 529, 638, -1, 467, - 89, 955, -1, 118, 859, -1, 353, 558, 659, 668, - 635, -1, 482, -1, 417, -1, 630, -1, -1, 178, - 671, 41, 193, 625, -1, 178, 671, 41, 528, 858, - 529, 631, -1, 41, 528, 858, 529, 631, -1, 647, - 626, -1, 295, 464, 627, -1, 634, -1, 661, -1, - 634, 661, -1, 661, 634, -1, -1, 295, 87, 138, - -1, 295, 87, 123, 375, -1, 295, 87, 334, 375, - -1, -1, 528, 641, 529, -1, 278, 207, -1, -1, - 94, 955, 666, -1, 666, -1, 86, -1, 95, -1, - 119, -1, 193, -1, 206, -1, 413, -1, 416, -1, - 31, -1, 662, -1, 641, 532, 662, -1, 467, 205, - 653, -1, 120, -1, 280, 120, -1, 209, 121, -1, - 209, 197, -1, 490, 637, -1, 490, 293, -1, 492, - 293, -1, -1, 528, 652, 529, -1, 646, 203, 640, - -1, 646, 151, 640, -1, -1, 565, -1, 280, 120, - -1, 120, -1, 209, 197, -1, 209, 121, -1, 280, - 469, -1, 278, 207, -1, 822, 660, -1, 821, 632, - 660, -1, 559, 649, -1, 559, 650, -1, 655, -1, - 652, 532, 655, -1, 559, -1, 651, -1, 669, -1, - 639, -1, 565, 517, 624, -1, 565, -1, 490, 645, - -1, -1, 667, -1, 667, 532, -1, -1, 559, -1, - 528, 663, 529, -1, -1, 660, 628, -1, -1, 295, - 123, 627, -1, 565, 517, 624, -1, 565, -1, 565, - 530, 565, 517, 624, -1, 565, 530, 565, -1, 658, - -1, 663, 532, 658, -1, 663, -1, 663, 532, -1, - 822, -1, 959, 963, 523, 451, -1, 396, 959, 963, - 523, 451, -1, 75, 528, 858, 529, 623, -1, 457, - 528, 664, 529, 656, 623, -1, 457, 642, 623, -1, - 335, 229, 528, 664, 529, 656, 623, -1, 335, 229, - 642, 623, -1, 171, 229, 528, 664, 529, 353, 558, - 659, 668, 635, 623, -1, 654, -1, 667, 532, 654, - -1, 252, 175, -1, 252, 314, -1, 252, 401, -1, - -1, 240, 558, 646, -1, 434, -1, 432, -1, 244, - 434, -1, 244, 432, -1, 180, 434, -1, 180, 432, - -1, 460, -1, -1, 34, -1, 60, 118, -1, 138, - 673, 194, 154, 675, 676, -1, 138, 673, 675, 676, - -1, 138, 674, 194, 154, 952, 676, -1, 138, 674, - 952, 676, -1, 138, 677, 955, 295, 962, 676, -1, - 138, 677, 194, 154, 955, 295, 962, 676, -1, 427, - -1, 390, -1, 176, -1, 249, -1, 249, 427, -1, - 480, -1, 254, 480, -1, 205, -1, 171, 427, -1, - 82, -1, 98, -1, 379, -1, 413, -1, 435, 383, - 313, -1, 435, 383, 130, -1, 435, 383, 433, -1, - 435, 383, 91, -1, 451, -1, 25, 257, -1, 148, - 445, -1, 158, -1, 171, 108, 494, -1, 341, -1, - 393, -1, 962, -1, 675, 532, 962, -1, 64, -1, - 366, -1, -1, 326, -1, 376, -1, 445, -1, 573, - 256, 222, 1015, 467, 792, 808, 688, 579, -1, 37, - 858, -1, -1, 528, 584, 529, -1, -1, 521, -1, - -1, 464, 395, 586, -1, 464, 395, 521, -1, 464, - 571, -1, 123, -1, 215, 680, 473, 528, 906, 529, - -1, 215, 571, 681, -1, 215, 118, 473, -1, 134, - 281, -1, 146, 683, -1, 858, -1, -1, 486, 253, - 679, 436, 682, -1, 60, 407, -1, 60, 431, -1, - -1, 486, 280, 253, 685, 679, 436, 682, -1, 684, - -1, 686, -1, 687, -1, 687, 688, -1, 101, 670, - 696, 558, 693, -1, 101, 670, 696, 194, 280, 154, - 558, 693, -1, 101, 300, 361, 670, 696, 558, 693, - -1, 101, 670, 696, 558, 695, -1, 101, 670, 696, - 194, 280, 154, 558, 695, -1, 101, 300, 361, 670, - 696, 558, 695, -1, 697, 41, 427, 716, -1, 697, - 41, 427, 715, -1, 691, -1, 692, 532, 691, -1, - 690, -1, 692, -1, 697, 41, 858, -1, 694, -1, - 695, 532, 694, -1, 176, -1, 249, -1, 528, 529, - -1, 528, 698, 532, 529, -1, 528, 698, 529, -1, - 699, -1, 698, 532, 699, -1, 965, 821, -1, 965, - 821, 13, 858, -1, 965, 821, 14, 858, -1, 573, - 464, 1015, 395, 586, 788, 1016, 579, -1, 99, 711, - 558, 659, 709, 703, 707, 713, 704, 610, 708, -1, - 99, 528, 714, 529, 440, 707, 713, 610, 708, -1, - 99, 174, 109, 559, 440, 559, 702, -1, -1, 528, - 379, 529, -1, 528, 108, 529, -1, 174, -1, 440, - -1, 705, 125, 561, -1, -1, 467, -1, -1, 41, - -1, -1, 340, -1, -1, 710, -1, 528, 1025, 529, - -1, 490, 293, -1, -1, 710, 712, -1, -1, 56, - -1, -1, 56, -1, 293, -1, 173, -1, 124, 706, - 561, -1, 285, 706, 561, -1, 103, -1, 189, -1, - 345, 706, 561, -1, 147, 706, 561, -1, 170, 345, - 663, -1, 170, 345, 521, -1, 315, 60, 663, -1, - 315, 60, 521, -1, 170, 280, 285, 663, -1, 170, - 285, 663, -1, 142, 561, -1, 561, -1, 414, -1, - 415, -1, 3, 530, 559, -1, 3, -1, 528, 858, - 529, -1, 863, -1, 716, -1, 715, -1, 528, 716, - 529, -1, 528, 715, 529, -1, 528, 1030, 529, -1, - 719, -1, 717, 742, -1, 717, 741, 779, 748, -1, - 717, 741, 747, 780, -1, 726, 717, -1, 726, 717, - 742, -1, 726, 717, 741, 779, 748, -1, 726, 717, - 741, 747, 780, -1, 719, -1, 715, -1, 388, 739, - 934, -1, -1, 388, 739, 934, 733, 788, 815, 768, - 777, 876, 778, 753, -1, 388, 738, 936, 733, 788, - 815, 768, 777, 876, 778, 753, -1, 174, 789, 718, - 733, 815, 768, 777, 876, 778, 753, -1, 174, 789, - 388, 738, 936, 733, 815, 768, 777, 876, 778, 753, - -1, 787, -1, 427, 809, -1, 717, 456, 736, 737, - 717, -1, 717, 456, 736, 717, -1, 717, 220, 736, - 717, -1, 717, 149, 736, 717, -1, 721, 792, 467, - 936, -1, 721, 792, 467, 936, 183, 60, 954, -1, - 721, 792, 183, 60, 954, -1, 721, 792, 295, 725, - -1, 721, 792, 295, 725, 183, 60, 954, -1, 721, - 792, 295, 725, 467, 936, -1, 721, 792, 295, 725, - 467, 936, 183, 60, 954, -1, 722, 792, 295, 936, - 222, 271, 955, 720, 954, -1, 722, 792, 295, 936, - -1, 472, -1, 473, -1, 321, -1, 323, -1, 462, - -1, 322, -1, 859, -1, 859, 201, 528, 716, 529, - -1, 795, -1, 723, -1, 724, 532, 723, -1, 724, - -1, 724, 532, -1, 490, 727, -1, 514, 727, -1, - 490, 351, 727, -1, 728, -1, 727, 532, 728, -1, - 955, 964, 729, 41, 732, 528, 969, 529, -1, 467, - 229, 528, 730, 529, -1, -1, 731, -1, 731, 532, - -1, 926, -1, 731, 532, 926, -1, 254, -1, 280, - 254, -1, -1, 222, 734, -1, -1, 434, 735, 558, - -1, 432, 735, 558, -1, 244, 434, 735, 558, -1, - 244, 432, 735, 558, -1, 180, 434, 735, 558, -1, - 180, 432, 735, 558, -1, 460, 735, 558, -1, 427, - 558, -1, 558, -1, 427, -1, -1, 31, -1, 133, - -1, -1, 60, 271, -1, 133, -1, 133, 295, 528, - 906, 529, -1, 31, -1, -1, 195, 287, -1, 364, - 287, -1, -1, 742, -1, -1, 301, 60, 743, -1, - 301, 60, 31, 745, 746, -1, 744, -1, 743, 532, - 744, -1, 858, 467, 900, 746, -1, 858, 745, 746, - -1, 42, -1, 127, -1, -1, 513, 166, -1, 513, - 234, -1, -1, 749, 750, -1, 750, 749, -1, 749, - -1, 750, -1, 747, -1, -1, 241, 762, -1, 241, - 762, 532, 763, -1, 164, 767, 764, 766, 296, -1, - 164, 767, 766, 296, -1, 292, 763, -1, 292, 764, - 766, -1, 4, -1, 9, -1, 863, -1, 751, 523, - -1, 751, 319, -1, 751, -1, 751, 375, -1, 467, - 377, 755, -1, -1, 559, -1, -1, 754, 528, 752, - 529, 758, -1, 752, -1, 752, 528, 559, 529, -1, - 752, 528, 559, 532, 9, 529, -1, 429, 755, -1, - 756, -1, -1, 360, 528, 9, 529, -1, -1, 439, - -1, 479, -1, 759, 14, 858, -1, 47, 528, 760, - 529, -1, -1, 858, -1, 31, -1, 858, 523, -1, - 4, 319, -1, 9, 319, -1, 858, -1, 860, -1, - 519, 765, -1, 520, 765, -1, 958, -1, 4, -1, - 374, -1, 375, -1, 166, -1, 277, -1, 183, 60, - 770, -1, 183, 60, 31, -1, -1, 771, -1, 769, - 532, 771, -1, 769, -1, 769, 532, -1, 858, -1, - 772, -1, 774, -1, 773, -1, 775, -1, 528, 529, - -1, 373, 528, 906, 529, -1, 104, 528, 906, 529, - -1, 184, 397, 528, 770, 529, -1, 184, -1, 185, - -1, 188, 858, -1, -1, 342, 858, -1, -1, 781, - -1, 169, 347, 296, -1, 779, -1, -1, 782, -1, - 781, 782, -1, 783, 784, 785, -1, 169, 464, -1, - 169, 278, 229, 464, -1, 169, 398, -1, 169, 229, - 398, -1, 290, 951, -1, -1, 284, -1, 402, 247, - -1, -1, 473, 528, 906, 529, -1, 786, 532, 528, - 906, 529, -1, 786, -1, 786, 532, -1, 174, 790, - -1, -1, 792, -1, 789, 532, 792, -1, 789, -1, - 789, 532, -1, 560, 19, -1, 809, 804, 761, 757, - -1, 791, 809, 761, 757, -1, 810, 805, 757, -1, - 791, 810, 757, -1, 787, 803, 757, -1, 235, 810, - 805, -1, 715, 804, 757, -1, 791, 715, 757, -1, - 235, 715, 804, -1, 802, -1, 528, 802, 529, 803, - -1, 791, 528, 802, 529, -1, 792, 321, 528, 936, - 169, 798, 793, 529, 804, -1, 792, 462, 794, 528, - 799, 169, 801, 529, 804, -1, 183, 60, 953, -1, - -1, 202, 287, -1, 150, 287, -1, -1, 859, 201, - 528, 936, 529, -1, 859, 201, 560, -1, 861, -1, - 864, -1, 528, 904, 529, -1, 796, 201, 528, 936, - 529, -1, 796, 201, 560, -1, 797, -1, 798, 797, - -1, 560, -1, 528, 953, 529, -1, 799, 201, 528, - 936, 529, -1, 800, -1, 801, 800, -1, 528, 802, - 529, -1, 792, 102, 227, 792, -1, 792, 806, 227, - 792, 808, -1, 792, 227, 792, 808, -1, 792, 274, - 806, 227, 792, -1, 792, 274, 227, 792, -1, 792, - 43, 806, 227, 792, 808, -1, 792, 43, 227, 792, - 808, -1, 792, 328, 227, 792, -1, 792, 38, 227, - 792, 808, -1, 792, 389, 227, 792, 808, -1, 41, - 560, 528, 953, 529, -1, 41, 560, -1, 559, 528, - 953, 529, -1, 559, -1, 803, -1, -1, 803, -1, - 41, 528, 816, 529, -1, 41, 560, 528, 816, 529, - -1, 559, 528, 816, 529, -1, -1, 175, 807, -1, - 238, 807, -1, 370, 807, -1, 389, -1, 38, -1, - 211, -1, 305, -1, -1, 467, 528, 953, 529, -1, - 295, 858, -1, 558, -1, 558, 521, -1, 296, 558, - -1, 296, 528, 558, 529, -1, 870, 814, -1, 375, - 174, 528, 812, 529, 814, -1, 870, 813, -1, 811, - -1, 812, 532, 811, -1, 41, 528, 816, 529, -1, - -1, 514, 302, -1, -1, 487, 858, -1, -1, 817, - -1, 816, 532, 817, -1, 560, 822, 818, -1, 81, - 962, -1, -1, 559, 822, -1, 819, 532, 559, 822, - -1, 374, -1, 420, -1, 822, -1, -1, 825, 824, - -1, 396, 825, 824, -1, 825, 40, 526, 958, 527, - -1, 396, 825, 40, 526, 958, 527, -1, 825, 40, - -1, 396, 825, 40, -1, 823, 824, -1, 820, 528, - 819, 529, 824, -1, 250, 528, 910, 529, 824, -1, - 456, 528, 819, 529, 824, -1, 3, 530, 3, -1, - 823, 530, 3, -1, 824, 526, 527, -1, 824, 526, - 958, 527, -1, -1, 827, -1, 829, -1, 831, -1, - 835, -1, 841, -1, 842, 857, -1, 842, 528, 958, - 529, -1, 829, -1, 832, -1, 836, -1, 841, -1, - 961, 828, -1, 528, 907, 529, -1, -1, 218, -1, - 219, -1, 403, -1, 55, -1, 348, -1, 167, 830, - -1, 137, 331, -1, 116, 828, -1, 113, 828, -1, - 288, 828, -1, 58, -1, 528, 958, 529, -1, -1, - 833, -1, 834, -1, 833, -1, 834, -1, 57, 840, - 528, 906, 529, -1, 57, 840, -1, 837, -1, 838, - -1, 837, -1, 838, -1, 839, 528, 958, 529, -1, - 839, -1, 73, 840, -1, 72, 840, -1, 474, -1, - 273, 73, 840, -1, 273, 72, 840, -1, 275, 840, - -1, 477, -1, -1, 439, 528, 958, 529, 843, -1, - 439, 843, -1, 438, 528, 958, 529, 843, -1, 438, - 843, -1, 221, -1, 514, 438, 511, -1, 492, 438, - 511, -1, -1, 508, -1, 509, -1, 268, -1, 269, - -1, 110, -1, 111, -1, 191, -1, 192, -1, 264, - -1, 265, -1, 384, -1, 385, -1, 262, -1, 263, - -1, 258, -1, 259, -1, 484, -1, 485, -1, 343, - -1, 344, -1, 114, -1, 115, -1, 70, -1, 69, - -1, 261, -1, 260, -1, 844, -1, 845, -1, 846, + 672, 427, 558, 528, 659, 529, 644, 646, 636, -1, + 101, 672, 427, 194, 280, 154, 558, 528, 659, 529, + 644, 646, 636, -1, 101, 300, 361, 672, 427, 558, + 528, 659, 529, 644, 646, 636, -1, -1, 623, 650, + -1, 667, -1, 1049, -1, 902, -1, 611, -1, 561, + -1, 279, -1, 528, 609, 529, -1, -1, 561, -1, + 278, 26, -1, 366, -1, 64, -1, 395, 285, -1, + 395, 118, -1, 94, 957, 629, -1, 629, -1, 643, + -1, 81, 964, -1, 280, 285, -1, 285, -1, 457, + 658, -1, 335, 229, 658, -1, 75, 528, 860, 529, + 638, -1, 467, 89, 957, -1, 118, 861, -1, 353, + 558, 661, 670, 635, -1, 482, -1, 417, -1, 630, + -1, -1, 178, 673, 41, 193, 625, -1, 178, 673, + 41, 528, 860, 529, 631, -1, 41, 528, 860, 529, + 631, -1, 649, 626, -1, 295, 464, 627, -1, 634, + -1, 663, -1, 634, 663, -1, 663, 634, -1, -1, + 295, 87, 138, -1, 295, 87, 123, 375, -1, 295, + 87, 334, 375, -1, -1, 528, 641, 529, -1, 278, + 207, -1, -1, 94, 957, 668, -1, 668, -1, 86, + -1, 95, -1, 119, -1, 193, -1, 206, -1, 413, + -1, 416, -1, 31, -1, 664, -1, 641, 532, 664, + -1, 467, 205, 655, -1, 120, -1, 280, 120, -1, + 209, 121, -1, 209, 197, -1, 644, 645, -1, -1, + 316, 60, 528, 908, 529, -1, 406, 60, 528, 908, + 529, -1, 490, 637, -1, 490, 293, -1, 492, 293, + -1, -1, 528, 654, 529, -1, 648, 203, 640, -1, + 648, 151, 640, -1, -1, 565, -1, 280, 120, -1, + 120, -1, 209, 197, -1, 209, 121, -1, 280, 469, + -1, 278, 207, -1, 824, 662, -1, 823, 632, 662, + -1, 559, 651, -1, 559, 652, -1, 657, -1, 654, + 532, 657, -1, 559, -1, 653, -1, 671, -1, 639, + -1, 565, 517, 624, -1, 565, -1, 490, 647, -1, + -1, 669, -1, 669, 532, -1, -1, 559, -1, 528, + 665, 529, -1, -1, 662, 628, -1, -1, 295, 123, + 627, -1, 565, 517, 860, -1, 565, -1, 565, 530, + 565, 517, 624, -1, 565, 530, 565, -1, 561, 517, + 860, -1, 561, -1, 660, -1, 665, 532, 660, -1, + 665, -1, 665, 532, -1, 824, -1, 961, 965, 523, + 451, -1, 396, 961, 965, 523, 451, -1, 75, 528, + 860, 529, 623, -1, 457, 528, 666, 529, 658, 623, + -1, 457, 642, 623, -1, 335, 229, 528, 666, 529, + 658, 623, -1, 335, 229, 642, 623, -1, 171, 229, + 528, 666, 529, 353, 558, 661, 670, 635, 623, -1, + 656, -1, 669, 532, 656, -1, 252, 175, -1, 252, + 314, -1, 252, 401, -1, -1, 240, 558, 648, -1, + 434, -1, 432, -1, 244, 434, -1, 244, 432, -1, + 180, 434, -1, 180, 432, -1, 460, -1, -1, 34, + -1, 60, 118, -1, 138, 675, 194, 154, 677, 678, + -1, 138, 675, 677, 678, -1, 138, 676, 194, 154, + 954, 678, -1, 138, 676, 954, 678, -1, 138, 679, + 957, 295, 964, 678, -1, 138, 679, 194, 154, 957, + 295, 964, 678, -1, 427, -1, 390, -1, 176, -1, + 249, -1, 249, 427, -1, 480, -1, 254, 480, -1, + 205, -1, 171, 427, -1, 82, -1, 98, -1, 379, + -1, 413, -1, 435, 383, 313, -1, 435, 383, 130, + -1, 435, 383, 433, -1, 435, 383, 91, -1, 451, + -1, 25, 257, -1, 148, 445, -1, 158, -1, 171, + 108, 494, -1, 341, -1, 393, -1, 964, -1, 677, + 532, 964, -1, 64, -1, 366, -1, -1, 326, -1, + 376, -1, 445, -1, 573, 256, 222, 1017, 467, 794, + 810, 690, 579, -1, 37, 860, -1, -1, 528, 584, + 529, -1, -1, 521, -1, -1, 464, 395, 586, -1, + 464, 395, 521, -1, 464, 571, -1, 123, -1, 215, + 682, 473, 528, 908, 529, -1, 215, 571, 683, -1, + 215, 118, 473, -1, 134, 281, -1, 146, 685, -1, + 860, -1, -1, 486, 253, 681, 436, 684, -1, 60, + 407, -1, 60, 431, -1, -1, 486, 280, 253, 687, + 681, 436, 684, -1, 686, -1, 688, -1, 689, -1, + 689, 690, -1, 101, 672, 698, 558, 695, -1, 101, + 672, 698, 194, 280, 154, 558, 695, -1, 101, 300, + 361, 672, 698, 558, 695, -1, 101, 672, 698, 558, + 697, -1, 101, 672, 698, 194, 280, 154, 558, 697, + -1, 101, 300, 361, 672, 698, 558, 697, -1, 699, + 41, 427, 718, -1, 699, 41, 427, 717, -1, 693, + -1, 694, 532, 693, -1, 692, -1, 694, -1, 699, + 41, 860, -1, 696, -1, 697, 532, 696, -1, 176, + -1, 249, -1, 528, 529, -1, 528, 700, 532, 529, + -1, 528, 700, 529, -1, 701, -1, 700, 532, 701, + -1, 967, 823, -1, 967, 823, 13, 860, -1, 967, + 823, 14, 860, -1, 573, 464, 1017, 395, 586, 790, + 1018, 579, -1, 99, 713, 558, 661, 711, 705, 709, + 715, 706, 610, 710, -1, 99, 528, 716, 529, 440, + 709, 715, 610, 710, -1, 99, 174, 109, 559, 440, + 559, 704, -1, -1, 528, 379, 529, -1, 528, 108, + 529, -1, 174, -1, 440, -1, 707, 125, 561, -1, + -1, 467, -1, -1, 41, -1, -1, 340, -1, -1, + 712, -1, 528, 1027, 529, -1, 490, 293, -1, -1, + 712, 714, -1, -1, 56, -1, -1, 56, -1, 293, + -1, 173, -1, 124, 708, 561, -1, 285, 708, 561, + -1, 103, -1, 189, -1, 345, 708, 561, -1, 147, + 708, 561, -1, 170, 345, 665, -1, 170, 345, 521, + -1, 315, 60, 665, -1, 315, 60, 521, -1, 170, + 280, 285, 665, -1, 170, 285, 665, -1, 142, 561, + -1, 561, -1, 414, -1, 415, -1, 3, 530, 559, + -1, 3, -1, 528, 860, 529, -1, 865, -1, 718, + -1, 717, -1, 528, 718, 529, -1, 528, 717, 529, + -1, 528, 1032, 529, -1, 721, -1, 719, 744, -1, + 719, 743, 781, 750, -1, 719, 743, 749, 782, -1, + 728, 719, -1, 728, 719, 744, -1, 728, 719, 743, + 781, 750, -1, 728, 719, 743, 749, 782, -1, 721, + -1, 717, -1, 388, 741, 936, -1, -1, 388, 741, + 936, 735, 790, 817, 770, 779, 878, 780, 755, -1, + 388, 740, 938, 735, 790, 817, 770, 779, 878, 780, + 755, -1, 174, 791, 720, 735, 817, 770, 779, 878, + 780, 755, -1, 174, 791, 388, 740, 938, 735, 817, + 770, 779, 878, 780, 755, -1, 789, -1, 427, 811, + -1, 719, 456, 738, 739, 719, -1, 719, 456, 738, + 719, -1, 719, 220, 738, 719, -1, 719, 149, 738, + 719, -1, 723, 794, 467, 938, -1, 723, 794, 467, + 938, 183, 60, 956, -1, 723, 794, 183, 60, 956, + -1, 723, 794, 295, 727, -1, 723, 794, 295, 727, + 183, 60, 956, -1, 723, 794, 295, 727, 467, 938, + -1, 723, 794, 295, 727, 467, 938, 183, 60, 956, + -1, 724, 794, 295, 938, 222, 271, 957, 722, 956, + -1, 724, 794, 295, 938, -1, 472, -1, 473, -1, + 321, -1, 323, -1, 462, -1, 322, -1, 861, -1, + 861, 201, 528, 718, 529, -1, 797, -1, 725, -1, + 726, 532, 725, -1, 726, -1, 726, 532, -1, 490, + 729, -1, 514, 729, -1, 490, 351, 729, -1, 730, + -1, 729, 532, 730, -1, 957, 966, 731, 41, 734, + 528, 971, 529, -1, 467, 229, 528, 732, 529, -1, + -1, 733, -1, 733, 532, -1, 928, -1, 733, 532, + 928, -1, 254, -1, 280, 254, -1, -1, 222, 736, + -1, -1, 434, 737, 558, -1, 432, 737, 558, -1, + 244, 434, 737, 558, -1, 244, 432, 737, 558, -1, + 180, 434, 737, 558, -1, 180, 432, 737, 558, -1, + 460, 737, 558, -1, 427, 558, -1, 558, -1, 427, + -1, -1, 31, -1, 133, -1, -1, 60, 271, -1, + 133, -1, 133, 295, 528, 908, 529, -1, 31, -1, + -1, 195, 287, -1, 364, 287, -1, -1, 744, -1, + -1, 301, 60, 745, -1, 301, 60, 31, 747, 748, + -1, 746, -1, 745, 532, 746, -1, 860, 467, 902, + 748, -1, 860, 747, 748, -1, 42, -1, 127, -1, + -1, 513, 166, -1, 513, 234, -1, -1, 751, 752, + -1, 752, 751, -1, 751, -1, 752, -1, 749, -1, + -1, 241, 764, -1, 241, 764, 532, 765, -1, 164, + 769, 766, 768, 296, -1, 164, 769, 768, 296, -1, + 292, 765, -1, 292, 766, 768, -1, 4, -1, 9, + -1, 865, -1, 753, 523, -1, 753, 319, -1, 753, + -1, 753, 375, -1, 467, 377, 757, -1, -1, 559, + -1, -1, 756, 528, 754, 529, 760, -1, 754, -1, + 754, 528, 559, 529, -1, 754, 528, 559, 532, 9, + 529, -1, 429, 757, -1, 758, -1, -1, 360, 528, + 9, 529, -1, -1, 439, -1, 479, -1, 761, 14, + 860, -1, 47, 528, 762, 529, -1, -1, 860, -1, + 31, -1, 860, 523, -1, 4, 319, -1, 9, 319, + -1, 860, -1, 862, -1, 519, 767, -1, 520, 767, + -1, 960, -1, 4, -1, 374, -1, 375, -1, 166, + -1, 277, -1, 183, 60, 772, -1, 183, 60, 31, + -1, -1, 773, -1, 771, 532, 773, -1, 771, -1, + 771, 532, -1, 860, -1, 774, -1, 776, -1, 775, + -1, 777, -1, 528, 529, -1, 373, 528, 908, 529, + -1, 104, 528, 908, 529, -1, 184, 397, 528, 772, + 529, -1, 184, -1, 185, -1, 188, 860, -1, -1, + 342, 860, -1, -1, 783, -1, 169, 347, 296, -1, + 781, -1, -1, 784, -1, 783, 784, -1, 785, 786, + 787, -1, 169, 464, -1, 169, 278, 229, 464, -1, + 169, 398, -1, 169, 229, 398, -1, 290, 953, -1, + -1, 284, -1, 402, 247, -1, -1, 473, 528, 908, + 529, -1, 788, 532, 528, 908, 529, -1, 788, -1, + 788, 532, -1, 174, 792, -1, -1, 794, -1, 791, + 532, 794, -1, 791, -1, 791, 532, -1, 560, 19, + -1, 811, 806, 763, 759, -1, 793, 811, 763, 759, + -1, 812, 807, 759, -1, 793, 812, 759, -1, 789, + 805, 759, -1, 235, 812, 807, -1, 717, 806, 759, + -1, 793, 717, 759, -1, 235, 717, 806, -1, 804, + -1, 528, 804, 529, 805, -1, 793, 528, 804, 529, + -1, 794, 321, 528, 938, 169, 800, 795, 529, 806, + -1, 794, 462, 796, 528, 801, 169, 803, 529, 806, + -1, 183, 60, 955, -1, -1, 202, 287, -1, 150, + 287, -1, -1, 861, 201, 528, 938, 529, -1, 861, + 201, 560, -1, 863, -1, 866, -1, 528, 906, 529, + -1, 798, 201, 528, 938, 529, -1, 798, 201, 560, + -1, 799, -1, 800, 799, -1, 560, -1, 528, 955, + 529, -1, 801, 201, 528, 938, 529, -1, 802, -1, + 803, 802, -1, 528, 804, 529, -1, 794, 102, 227, + 794, -1, 794, 808, 227, 794, 810, -1, 794, 227, + 794, 810, -1, 794, 274, 808, 227, 794, -1, 794, + 274, 227, 794, -1, 794, 43, 808, 227, 794, 810, + -1, 794, 43, 227, 794, 810, -1, 794, 328, 227, + 794, -1, 794, 38, 227, 794, 810, -1, 794, 389, + 227, 794, 810, -1, 41, 560, 528, 955, 529, -1, + 41, 560, -1, 559, 528, 955, 529, -1, 559, -1, + 805, -1, -1, 805, -1, 41, 528, 818, 529, -1, + 41, 560, 528, 818, 529, -1, 559, 528, 818, 529, + -1, -1, 175, 809, -1, 238, 809, -1, 370, 809, + -1, 389, -1, 38, -1, 211, -1, 305, -1, -1, + 467, 528, 955, 529, -1, 295, 860, -1, 558, -1, + 558, 521, -1, 296, 558, -1, 296, 528, 558, 529, + -1, 872, 816, -1, 375, 174, 528, 814, 529, 816, + -1, 872, 815, -1, 813, -1, 814, 532, 813, -1, + 41, 528, 818, 529, -1, -1, 514, 302, -1, -1, + 487, 860, -1, -1, 819, -1, 818, 532, 819, -1, + 560, 824, 820, -1, 81, 964, -1, -1, 559, 824, + -1, 821, 532, 559, 824, -1, 374, -1, 420, -1, + 824, -1, -1, 827, 826, -1, 396, 827, 826, -1, + 827, 40, 526, 960, 527, -1, 825, 40, 526, 960, + 527, -1, 396, 827, 40, 526, 960, 527, -1, 396, + 825, 40, 526, 960, 527, -1, 827, 40, -1, 825, + 40, -1, 396, 827, 40, -1, 396, 825, 40, -1, + 825, 826, -1, 822, 528, 821, 529, 826, -1, 250, + 528, 912, 529, 826, -1, 456, 528, 821, 529, 826, + -1, 3, 530, 3, -1, 825, 530, 3, -1, 826, + 526, 527, -1, 826, 526, 960, 527, -1, -1, 829, + -1, 831, -1, 833, -1, 837, -1, 843, -1, 844, + 859, -1, 844, 528, 960, 529, -1, 831, -1, 834, + -1, 838, -1, 843, -1, 963, 830, -1, 528, 909, + 529, -1, -1, 218, -1, 219, -1, 403, -1, 55, + -1, 348, -1, 167, 832, -1, 137, 331, -1, 116, + 830, -1, 113, 830, -1, 288, 830, -1, 58, -1, + 528, 960, 529, -1, -1, 835, -1, 836, -1, 835, + -1, 836, -1, 57, 842, 528, 908, 529, -1, 57, + 842, -1, 839, -1, 840, -1, 839, -1, 840, -1, + 841, 528, 960, 529, -1, 841, -1, 73, 842, -1, + 72, 842, -1, 474, -1, 273, 73, 842, -1, 273, + 72, 842, -1, 275, 842, -1, 477, -1, -1, 439, + 528, 960, 529, 845, -1, 439, 845, -1, 438, 528, + 960, 529, 845, -1, 438, 845, -1, 221, -1, 514, + 438, 511, -1, 492, 438, 511, -1, -1, 508, -1, + 509, -1, 268, -1, 269, -1, 110, -1, 111, -1, + 191, -1, 192, -1, 264, -1, 265, -1, 384, -1, + 385, -1, 262, -1, 263, -1, 258, -1, 259, -1, + 484, -1, 485, -1, 343, -1, 344, -1, 114, -1, + 115, -1, 70, -1, 69, -1, 261, -1, 260, -1, + 846, -1, 847, -1, 848, -1, 849, -1, 850, -1, + 851, -1, 852, -1, 853, -1, 854, -1, 855, -1, + 856, -1, 857, -1, 858, -1, 846, 440, 847, -1, + 848, 440, 849, -1, 848, 440, 850, -1, 848, 440, + 851, -1, 849, 440, 850, -1, 849, 440, 851, -1, + 850, 440, 851, -1, -1, 862, -1, 860, 11, 824, + -1, 860, 81, 964, -1, 860, 47, 438, 511, 860, + -1, 519, 860, -1, 520, 860, -1, 860, 519, 860, + -1, 860, 520, 860, -1, 860, 521, 860, -1, 860, + 522, 860, -1, 860, 15, 860, -1, 860, 523, 860, + -1, 860, 524, 860, -1, 860, 16, 860, -1, 860, + 515, 860, -1, 860, 516, 860, -1, 860, 517, 860, + -1, 860, 20, 860, -1, 860, 21, 860, -1, 860, + 22, 860, -1, 860, 901, 860, -1, 901, 860, -1, + 860, 901, -1, 860, 37, 860, -1, 860, 300, 860, + -1, 280, 860, -1, 512, 860, -1, 860, 179, 860, + -1, 860, 240, 860, -1, 860, 240, 860, 147, 860, + -1, 860, 512, 240, 860, -1, 860, 512, 240, 860, + 147, 860, -1, 860, 196, 860, -1, 860, 196, 860, + 147, 860, -1, 860, 512, 196, 860, -1, 860, 512, + 196, 860, 147, 860, -1, 860, 400, 440, 860, -1, + 860, 400, 440, 860, 147, 860, -1, 860, 512, 400, + 440, 860, -1, 860, 512, 400, 440, 860, 147, 860, + -1, 860, 224, 285, -1, 860, 225, -1, 860, 224, + 280, 285, -1, 860, 280, 285, -1, 860, 283, -1, + 231, 954, 19, 860, -1, 860, 17, 860, -1, 860, + 18, 860, -1, 890, 307, 890, -1, 860, 224, 447, + -1, 860, 224, 280, 447, -1, 860, 224, 162, -1, + 860, 224, 280, 162, -1, 860, 224, 458, -1, 860, + 224, 280, 458, -1, 860, 224, 133, 174, 860, -1, + 860, 224, 280, 133, 174, 860, -1, 860, 224, 290, + 528, 912, 529, -1, 860, 224, 280, 290, 528, 912, + 529, -1, 860, 54, 935, 861, 37, 860, -1, 860, + 512, 54, 935, 861, 37, 860, -1, 860, 54, 424, + 861, 37, 860, -1, 860, 512, 54, 424, 861, 37, + 860, -1, 860, 201, 922, -1, 860, 512, 201, 922, + -1, 860, 903, 898, 717, -1, 860, 903, 898, 528, + 860, 529, -1, 118, -1, 84, 528, 860, 529, -1, + 461, 528, 860, 529, -1, 521, 84, 528, 860, 529, + -1, 521, 944, 948, 952, -1, 559, 530, 521, 944, + 948, 952, -1, 862, -1, 861, 11, 824, -1, 519, + 861, -1, 520, 861, -1, 861, 519, 861, -1, 861, + 520, 861, -1, 861, 521, 861, -1, 861, 522, 861, + -1, 861, 15, 861, -1, 861, 523, 861, -1, 861, + 524, 861, -1, 861, 16, 861, -1, 861, 515, 861, + -1, 861, 516, 861, -1, 861, 517, 861, -1, 861, + 20, 861, -1, 861, 21, 861, -1, 861, 22, 861, + -1, 861, 901, 861, -1, 901, 861, -1, 861, 901, + -1, 861, 224, 133, 174, 861, -1, 861, 224, 280, + 133, 174, 861, -1, 861, 224, 290, 528, 912, 529, + -1, 861, 224, 280, 290, 528, 912, 529, -1, 863, + -1, 864, 934, -1, 929, -1, 959, -1, 717, -1, + 717, 562, -1, 154, 717, -1, 778, 528, 908, 529, + -1, 528, 860, 529, -1, 866, -1, 890, -1, 533, + -1, 10, -1, 534, 565, -1, 865, -1, 868, -1, + 869, -1, 871, -1, 923, -1, 867, -1, 874, -1, + 40, 717, -1, 40, 526, 909, 527, -1, 535, 9, + -1, 526, 909, 527, -1, 536, 893, 537, -1, 250, + 536, 897, 537, -1, 958, 528, 529, -1, 958, 528, + 744, 742, 529, -1, 958, 528, 910, 743, 742, 529, + -1, 958, 528, 476, 911, 743, 742, 529, -1, 958, + 528, 910, 532, 476, 911, 743, 742, 529, -1, 958, + 528, 31, 910, 743, 742, 529, -1, 958, 528, 133, + 910, 743, 742, 529, -1, 870, 875, 876, 877, 881, + -1, 873, -1, 870, -1, 873, -1, 82, 169, 528, + 860, 529, -1, 67, 528, 860, 41, 824, 529, -1, + 450, 528, 860, 41, 824, 529, -1, 161, 528, 913, + 529, -1, 308, 528, 915, 529, -1, 327, 528, 917, + 529, -1, 422, 528, 918, 529, -1, 444, 528, 860, + 41, 824, 529, -1, 446, 528, 59, 921, 529, -1, + 446, 528, 236, 921, 529, -1, 446, 528, 441, 921, + 529, -1, 446, 528, 921, 529, -1, 286, 528, 860, + 532, 860, 529, -1, 80, 528, 908, 529, -1, 526, + 860, 169, 954, 201, 860, 527, -1, 526, 860, 169, + 954, 201, 862, 194, 860, 527, -1, 491, 183, 528, + 744, 529, -1, -1, 165, 528, 487, 860, 529, -1, + 165, 528, 860, 529, -1, -1, 157, -1, -1, 489, + 879, -1, -1, 880, -1, 879, 532, 880, -1, 559, + 41, 882, -1, 306, 882, -1, 306, 559, -1, -1, + 528, 883, 884, 743, 885, 529, -1, 559, -1, -1, + 315, 60, 907, -1, -1, 346, 886, 888, -1, 375, + 886, 888, -1, 186, 886, 888, -1, -1, 887, -1, + 54, 887, 37, 887, -1, 453, 330, -1, 453, 168, + -1, 105, 374, -1, 860, 330, -1, 860, 168, -1, + 150, 105, 374, -1, 150, 183, -1, 150, 437, -1, + 150, 278, 303, -1, -1, 374, 528, 908, 529, -1, + 374, 528, 529, -1, 889, -1, 528, 907, 532, 860, + 529, -1, 560, 19, 860, -1, 891, -1, 892, 532, + 891, -1, 892, -1, 892, 532, -1, 860, 19, 860, + -1, 894, -1, 895, 532, 894, -1, 895, -1, 895, + 532, -1, 896, -1, -1, 39, -1, 405, -1, 31, + -1, 8, -1, 900, -1, 519, -1, 520, -1, 521, + -1, 522, -1, 15, -1, 523, -1, 524, -1, 16, + -1, 515, -1, 516, -1, 517, -1, 20, -1, 21, + -1, 22, -1, 8, -1, 297, 528, 904, 529, -1, + 899, -1, 297, 528, 904, 529, -1, 899, -1, 297, + 528, 904, 529, -1, 240, -1, 512, 240, -1, 179, + -1, 512, 179, -1, 196, -1, 512, 196, -1, 899, + -1, 559, 530, 904, -1, 862, -1, 905, 532, 862, + -1, 905, -1, 905, 532, -1, 860, -1, 907, 532, + 860, -1, 907, -1, 907, 532, -1, 908, -1, -1, + 911, -1, 910, 532, 911, -1, 860, -1, 967, 13, + 860, -1, 967, 14, 860, -1, 824, -1, 912, 532, + 824, -1, 914, 174, 860, -1, -1, 3, -1, 846, -1, 847, -1, 848, -1, 849, -1, 850, -1, 851, -1, 852, -1, 853, -1, 854, -1, 855, -1, 856, - -1, 844, 440, 845, -1, 846, 440, 847, -1, 846, - 440, 848, -1, 846, 440, 849, -1, 847, 440, 848, - -1, 847, 440, 849, -1, 848, 440, 849, -1, -1, - 860, -1, 858, 11, 822, -1, 858, 81, 962, -1, - 858, 47, 438, 511, 858, -1, 519, 858, -1, 520, - 858, -1, 858, 519, 858, -1, 858, 520, 858, -1, - 858, 521, 858, -1, 858, 522, 858, -1, 858, 15, - 858, -1, 858, 523, 858, -1, 858, 524, 858, -1, - 858, 16, 858, -1, 858, 515, 858, -1, 858, 516, - 858, -1, 858, 517, 858, -1, 858, 20, 858, -1, - 858, 21, 858, -1, 858, 22, 858, -1, 858, 899, - 858, -1, 899, 858, -1, 858, 899, -1, 858, 37, - 858, -1, 858, 300, 858, -1, 280, 858, -1, 512, - 858, -1, 858, 179, 858, -1, 858, 240, 858, -1, - 858, 240, 858, 147, 858, -1, 858, 512, 240, 858, - -1, 858, 512, 240, 858, 147, 858, -1, 858, 196, - 858, -1, 858, 196, 858, 147, 858, -1, 858, 512, - 196, 858, -1, 858, 512, 196, 858, 147, 858, -1, - 858, 400, 440, 858, -1, 858, 400, 440, 858, 147, - 858, -1, 858, 512, 400, 440, 858, -1, 858, 512, - 400, 440, 858, 147, 858, -1, 858, 224, 285, -1, - 858, 225, -1, 858, 224, 280, 285, -1, 858, 280, - 285, -1, 858, 283, -1, 231, 952, 19, 858, -1, - 858, 17, 858, -1, 858, 18, 858, -1, 888, 307, - 888, -1, 858, 224, 447, -1, 858, 224, 280, 447, - -1, 858, 224, 162, -1, 858, 224, 280, 162, -1, - 858, 224, 458, -1, 858, 224, 280, 458, -1, 858, - 224, 133, 174, 858, -1, 858, 224, 280, 133, 174, - 858, -1, 858, 224, 290, 528, 910, 529, -1, 858, - 224, 280, 290, 528, 910, 529, -1, 858, 54, 933, - 859, 37, 858, -1, 858, 512, 54, 933, 859, 37, - 858, -1, 858, 54, 424, 859, 37, 858, -1, 858, - 512, 54, 424, 859, 37, 858, -1, 858, 201, 920, - -1, 858, 512, 201, 920, -1, 858, 901, 896, 715, - -1, 858, 901, 896, 528, 858, 529, -1, 118, -1, - 84, 528, 858, 529, -1, 461, 528, 858, 529, -1, - 521, 84, 528, 858, 529, -1, 521, 942, 946, 950, - -1, 559, 530, 521, 942, 946, 950, -1, 860, -1, - 859, 11, 822, -1, 519, 859, -1, 520, 859, -1, - 859, 519, 859, -1, 859, 520, 859, -1, 859, 521, - 859, -1, 859, 522, 859, -1, 859, 15, 859, -1, - 859, 523, 859, -1, 859, 524, 859, -1, 859, 16, - 859, -1, 859, 515, 859, -1, 859, 516, 859, -1, - 859, 517, 859, -1, 859, 20, 859, -1, 859, 21, - 859, -1, 859, 22, 859, -1, 859, 899, 859, -1, - 899, 859, -1, 859, 899, -1, 859, 224, 133, 174, - 859, -1, 859, 224, 280, 133, 174, 859, -1, 859, - 224, 290, 528, 910, 529, -1, 859, 224, 280, 290, - 528, 910, 529, -1, 861, -1, 862, 932, -1, 927, - -1, 957, -1, 715, -1, 715, 562, -1, 154, 715, - -1, 776, 528, 906, 529, -1, 528, 858, 529, -1, - 864, -1, 888, -1, 533, -1, 10, -1, 534, 565, - -1, 863, -1, 866, -1, 867, -1, 869, -1, 921, - -1, 865, -1, 872, -1, 40, 715, -1, 40, 526, - 907, 527, -1, 535, 9, -1, 526, 907, 527, -1, - 536, 891, 537, -1, 250, 536, 895, 537, -1, 956, - 528, 529, -1, 956, 528, 742, 740, 529, -1, 956, - 528, 908, 741, 740, 529, -1, 956, 528, 476, 909, - 741, 740, 529, -1, 956, 528, 908, 532, 476, 909, - 741, 740, 529, -1, 956, 528, 31, 908, 741, 740, - 529, -1, 956, 528, 133, 908, 741, 740, 529, -1, - 868, 873, 874, 875, 879, -1, 871, -1, 868, -1, - 871, -1, 82, 169, 528, 858, 529, -1, 67, 528, - 858, 41, 822, 529, -1, 450, 528, 858, 41, 822, - 529, -1, 161, 528, 911, 529, -1, 308, 528, 913, - 529, -1, 327, 528, 915, 529, -1, 422, 528, 916, - 529, -1, 444, 528, 858, 41, 822, 529, -1, 446, - 528, 59, 919, 529, -1, 446, 528, 236, 919, 529, - -1, 446, 528, 441, 919, 529, -1, 446, 528, 919, - 529, -1, 286, 528, 858, 532, 858, 529, -1, 80, - 528, 906, 529, -1, 526, 858, 169, 952, 201, 858, - 527, -1, 526, 858, 169, 952, 201, 860, 194, 858, - 527, -1, 491, 183, 528, 742, 529, -1, -1, 165, - 528, 487, 858, 529, -1, 165, 528, 858, 529, -1, - -1, 157, -1, -1, 489, 877, -1, -1, 878, -1, - 877, 532, 878, -1, 559, 41, 880, -1, 306, 880, - -1, 306, 559, -1, -1, 528, 881, 882, 741, 883, - 529, -1, 559, -1, -1, 315, 60, 905, -1, -1, - 346, 884, 886, -1, 375, 884, 886, -1, 186, 884, - 886, -1, -1, 885, -1, 54, 885, 37, 885, -1, - 453, 330, -1, 453, 168, -1, 105, 374, -1, 858, - 330, -1, 858, 168, -1, 150, 105, 374, -1, 150, - 183, -1, 150, 437, -1, 150, 278, 303, -1, -1, - 374, 528, 906, 529, -1, 374, 528, 529, -1, 887, - -1, 528, 905, 532, 858, 529, -1, 560, 19, 858, - -1, 889, -1, 890, 532, 889, -1, 890, -1, 890, - 532, -1, 858, 19, 858, -1, 892, -1, 893, 532, - 892, -1, 893, -1, 893, 532, -1, 894, -1, -1, - 39, -1, 405, -1, 31, -1, 8, -1, 898, -1, - 519, -1, 520, -1, 521, -1, 522, -1, 15, -1, - 523, -1, 524, -1, 16, -1, 515, -1, 516, -1, - 517, -1, 20, -1, 21, -1, 22, -1, 8, -1, - 297, 528, 902, 529, -1, 897, -1, 297, 528, 902, - 529, -1, 897, -1, 297, 528, 902, 529, -1, 240, - -1, 512, 240, -1, 179, -1, 512, 179, -1, 196, - -1, 512, 196, -1, 897, -1, 559, 530, 902, -1, - 860, -1, 903, 532, 860, -1, 903, -1, 903, 532, - -1, 858, -1, 905, 532, 858, -1, 905, -1, 905, - 532, -1, 906, -1, -1, 909, -1, 908, 532, 909, - -1, 858, -1, 965, 13, 858, -1, 965, 14, 858, - -1, 822, -1, 910, 532, 822, -1, 912, 174, 858, - -1, -1, 3, -1, 844, -1, 845, -1, 846, -1, - 847, -1, 848, -1, 849, -1, 850, -1, 851, -1, - 852, -1, 853, -1, 854, -1, 855, -1, 856, -1, - 561, -1, 858, 914, 917, 918, -1, 858, 914, 917, - -1, 324, 858, -1, 859, 201, 859, -1, -1, 858, - 917, 918, -1, 858, 918, 917, -1, 858, 917, -1, - 858, 918, -1, 905, -1, -1, 174, 858, -1, 169, - 858, -1, 858, 174, 906, -1, 174, 906, -1, 906, - -1, 715, -1, 528, 906, 529, -1, 927, -1, 864, - -1, 66, 925, 922, 924, 144, -1, 923, -1, 922, - 923, -1, 486, 858, 436, 858, -1, 140, 858, -1, - -1, 858, -1, -1, 559, -1, 559, -1, 559, 562, - -1, 526, 858, 527, -1, 526, 928, 19, 928, 527, - -1, 526, 928, 19, 928, 19, 928, 527, -1, 526, - 928, 19, 520, 19, 928, 527, -1, 858, -1, -1, - -1, 929, 563, -1, -1, 528, 529, -1, 528, 908, - 529, -1, 530, 564, 930, -1, 526, 858, 527, -1, - 526, 928, 19, 928, 527, -1, 526, 928, 19, 928, - 19, 928, 527, -1, 526, 928, 19, 520, 19, 928, - 527, -1, -1, 932, 931, -1, 46, -1, -1, 936, - -1, -1, 937, -1, 935, 532, 937, -1, 935, -1, - 935, 532, -1, 858, 41, 966, -1, 858, 3, -1, - 858, -1, 559, 19, 858, -1, 150, 528, 941, 529, - -1, 150, 939, -1, 560, -1, 939, 530, 560, -1, - 939, -1, 940, 532, 939, -1, 940, -1, 940, 532, - -1, 938, -1, -1, 858, 41, 559, -1, 943, -1, - 944, 532, 943, -1, 944, -1, 944, 532, -1, 361, - 528, 945, 529, -1, 361, 943, -1, -1, 939, 41, - 559, -1, 947, -1, 948, 532, 947, -1, 948, -1, - 948, 532, -1, 359, 528, 949, 529, -1, 359, 947, - -1, -1, 558, -1, 951, 532, 558, -1, 955, -1, - 952, 532, 955, -1, 952, -1, 952, 532, -1, 953, - -1, 528, 953, 529, -1, 560, -1, 960, -1, 559, - 562, -1, 958, -1, 4, -1, 561, 929, -1, 6, - -1, 7, -1, 956, 561, -1, 956, 528, 908, 741, - 740, 529, 561, -1, 826, 561, -1, 842, 528, 858, - 529, 857, -1, 842, 958, 857, -1, 842, 561, 857, - -1, 447, -1, 162, -1, 285, -1, 9, -1, 3, - -1, 1041, -1, 1046, -1, 3, -1, 1041, -1, 1043, - -1, 3, -1, 1041, -1, 1044, -1, 559, -1, 559, - 963, -1, 530, 564, -1, 963, 530, 564, -1, 528, - 953, 529, -1, -1, 959, -1, 565, -1, 5, -1, - 332, 955, 968, 41, 969, -1, 528, 910, 529, -1, - -1, 714, -1, 568, -1, 700, -1, 701, -1, 1014, - -1, 1030, -1, 101, 379, 558, 971, -1, 101, 379, - 194, 280, 154, 558, 971, -1, 101, 300, 361, 379, - 558, 971, -1, 971, 972, -1, -1, 622, -1, 973, - -1, 594, -1, 1036, -1, 101, 979, 205, 976, 977, - 295, 558, 975, 528, 587, 529, 978, 815, -1, 101, - 979, 205, 976, 194, 280, 154, 653, 295, 558, 975, - 528, 587, 529, 978, 815, -1, 559, -1, 467, 974, - -1, -1, 90, -1, -1, 653, -1, -1, 490, 637, - -1, -1, 457, -1, -1, 33, 427, 809, 395, 379, - 955, -1, 33, 427, 194, 154, 809, 395, 379, 955, - -1, 33, 390, 558, 395, 379, 955, -1, 33, 390, - 194, 154, 558, 395, 379, 955, -1, 33, 480, 558, - 395, 379, 955, -1, 33, 480, 194, 154, 558, 395, - 379, 955, -1, 170, 76, 982, -1, 76, 982, -1, - 559, -1, -1, 85, 295, 985, 558, 224, 984, -1, - 85, 295, 83, 858, 224, 984, -1, 561, -1, 285, - -1, 427, -1, 390, -1, 176, -1, 249, -1, 249, - 427, -1, 480, -1, 109, -1, 205, -1, 379, -1, - 451, -1, 156, 109, 561, 708, -1, 156, 109, 559, - 440, 561, 708, -1, 200, 109, 561, -1, 155, 991, - -1, 155, 995, 989, 991, -1, 155, 478, 991, -1, - 155, 528, 994, 529, 991, -1, 478, -1, -1, 996, - -1, 611, -1, -1, 980, -1, 608, -1, 542, -1, - 1035, -1, 981, -1, 701, -1, 1038, -1, 689, -1, - 970, -1, 594, -1, 622, -1, 589, -1, 557, -1, - 1014, -1, 672, -1, 604, -1, 973, -1, 568, -1, - 1005, -1, 678, -1, 593, -1, 967, -1, 566, -1, - 714, -1, 618, -1, 700, -1, 603, -1, 1009, -1, - 1027, -1, 999, -1, 1030, -1, 1036, -1, 3, -1, - 1041, -1, 1045, -1, 992, -1, 561, -1, 997, -1, - 994, 532, 997, -1, 36, -1, 35, -1, 447, -1, - 162, -1, 295, -1, 993, -1, 998, 990, -1, 992, - -1, 995, -1, 395, 1000, -1, 395, 244, 1000, -1, - 395, 394, 1000, -1, 395, 180, 1000, -1, 395, 475, - 1000, -1, 1001, -1, 1034, 174, 105, -1, 438, 511, - 1003, -1, 379, 561, -1, 1034, 440, 1004, -1, 1034, - 517, 1004, -1, 858, -1, 561, -1, 3, -1, 842, - 561, 857, -1, 842, 528, 958, 529, 561, -1, 611, - -1, 118, -1, 244, -1, 1002, -1, 1004, 532, 1002, - -1, 243, 1007, -1, 1006, 216, 1007, 1008, -1, 1006, - 216, 1007, 174, 559, 1008, -1, 1006, 216, 1007, 174, - 561, 1008, -1, -1, 170, -1, 561, -1, 559, -1, - -1, 479, 561, -1, 479, 559, -1, 468, 1011, 1013, - 989, -1, 468, 1011, 1013, 989, 558, 964, -1, 468, - 1011, 1013, 989, 1018, -1, 468, 528, 1012, 529, -1, - 468, 528, 1012, 529, 558, 964, -1, 995, -1, 478, - -1, 173, -1, 175, -1, 3, -1, 175, -1, -1, - 1010, -1, 1012, 532, 1010, -1, 173, -1, -1, 573, - 123, 174, 1015, 1017, 1016, 579, -1, 448, 735, 1015, - -1, 809, -1, 809, 559, -1, 809, 41, 559, -1, - 487, 858, -1, -1, 467, 790, -1, -1, 995, 989, - -1, 995, 989, 558, 964, -1, 48, 1021, 561, 1022, - 1026, -1, 48, 194, 280, 154, 1021, 561, 1022, 1026, - -1, 48, 300, 361, 1021, 561, 1022, 1026, -1, 129, - 565, -1, 129, 109, 565, -1, 129, 109, 194, 154, - 565, -1, 109, -1, -1, 41, 559, -1, -1, 858, - -1, -1, 565, 1023, -1, 1024, -1, 1025, 532, 1024, - -1, 528, 1025, 529, -1, -1, 363, 1029, -1, 363, - 244, 1029, -1, 363, 394, 1029, -1, 363, 180, 1029, - -1, 363, 475, 1029, -1, 1034, -1, 31, -1, 1028, - -1, 438, 511, -1, 442, 226, 239, -1, 1032, 714, - -1, 423, 714, -1, 423, 558, -1, 1032, 428, 174, - 558, -1, 1032, 558, -1, 1032, 438, 511, -1, 1032, - 442, 226, 239, -1, 1032, 31, 1033, -1, 1032, -1, - 128, -1, 127, -1, 399, -1, 1031, -1, 428, -1, - -1, 559, -1, 1034, 530, 559, -1, 62, 868, -1, - 101, 670, 480, 558, 659, 978, 41, 714, 1037, -1, - 101, 670, 480, 194, 280, 154, 558, 659, 978, 41, - 714, 1037, -1, 101, 300, 361, 670, 480, 558, 659, - 978, 41, 714, 1037, -1, 101, 670, 351, 480, 558, - 528, 663, 529, 978, 41, 714, 1037, -1, 101, 300, - 361, 670, 351, 480, 558, 528, 663, 529, 978, 41, - 714, 1037, -1, 490, 75, 298, -1, 490, 65, 75, - 298, -1, 490, 244, 75, 298, -1, -1, 101, 670, - 427, 1040, 41, 714, 1039, -1, 101, 670, 427, 194, - 280, 154, 1040, 41, 714, 1039, -1, 101, 300, 361, - 670, 427, 1040, 41, 714, 1039, -1, 490, 108, -1, - 490, 278, 108, -1, -1, 558, 659, 644, 636, -1, - 23, -1, 24, -1, 25, -1, 26, -1, 27, -1, - 28, -1, 29, -1, 30, -1, 32, -1, 33, -1, - 34, -1, 44, -1, 45, -1, 48, -1, 49, -1, - 51, -1, 52, -1, 53, -1, 61, -1, 62, -1, - 63, -1, 64, -1, 65, -1, 68, -1, 69, -1, - 70, -1, 71, -1, 74, -1, 76, -1, 77, -1, - 78, -1, 79, -1, 85, -1, 86, -1, 87, -1, - 88, -1, 89, -1, 91, -1, 92, -1, 93, -1, - 95, -1, 96, -1, 97, -1, 98, -1, 99, -1, - 100, -1, 103, -1, 104, -1, 105, -1, 106, -1, - 107, -1, 108, -1, 109, -1, 110, -1, 111, -1, - 112, -1, 114, -1, 115, -1, 117, -1, 119, -1, - 121, -1, 122, -1, 123, -1, 124, -1, 125, -1, - 126, -1, 129, -1, 130, -1, 131, -1, 132, -1, - 135, -1, 136, -1, 137, -1, 138, -1, 139, -1, - 141, -1, 142, -1, 143, -1, 145, -1, 146, -1, - 147, -1, 148, -1, 150, -1, 151, -1, 152, -1, - 153, -1, 155, -1, 156, -1, 157, -1, 158, -1, - 159, -1, 160, -1, 163, -1, 165, -1, 166, -1, - 168, -1, 170, -1, 172, -1, 176, -1, 177, -1, - 180, -1, 181, -1, 182, -1, 186, -1, 187, -1, - 189, -1, 190, -1, 191, -1, 192, -1, 193, -1, - 194, -1, 195, -1, 197, -1, 198, -1, 199, -1, - 200, -1, 202, -1, 203, -1, 204, -1, 205, -1, - 206, -1, 207, -1, 208, -1, 210, -1, 213, -1, - 214, -1, 215, -1, 216, -1, 217, -1, 223, -1, - 226, -1, 228, -1, 229, -1, 230, -1, 232, -1, - 233, -1, 234, -1, 237, -1, 239, -1, 242, -1, - 243, -1, 244, -1, 245, -1, 246, -1, 247, -1, - 248, -1, 249, -1, 251, -1, 252, -1, 253, -1, - 254, -1, 255, -1, 256, -1, 257, -1, 258, -1, - 259, -1, 260, -1, 261, -1, 262, -1, 263, -1, - 264, -1, 265, -1, 266, -1, 267, -1, 268, -1, - 269, -1, 270, -1, 271, -1, 272, -1, 276, -1, - 277, -1, 278, -1, 281, -1, 282, -1, 284, -1, - 287, -1, 289, -1, 290, -1, 291, -1, 293, -1, - 294, -1, 297, -1, 298, -1, 299, -1, 302, -1, - 303, -1, 306, -1, 309, -1, 310, -1, 311, -1, - 312, -1, 313, -1, 314, -1, 315, -1, 316, -1, - 317, -1, 318, -1, 319, -1, 320, -1, 325, -1, - 326, -1, 329, -1, 330, -1, 332, -1, 333, -1, - 334, -1, 336, -1, 337, -1, 338, -1, 339, -1, - 340, -1, 341, -1, 343, -1, 344, -1, 345, -1, - 346, -1, 347, -1, 349, -1, 350, -1, 351, -1, - 352, -1, 354, -1, 355, -1, 356, -1, 357, -1, - 358, -1, 359, -1, 360, -1, 361, -1, 362, -1, - 363, -1, 364, -1, 365, -1, 366, -1, 368, -1, - 369, -1, 371, -1, 372, -1, 373, -1, 375, -1, - 376, -1, 377, -1, 378, -1, 379, -1, 380, -1, - 381, -1, 382, -1, 383, -1, 384, -1, 385, -1, - 386, -1, 387, -1, 390, -1, 391, -1, 392, -1, - 393, -1, 394, -1, 395, -1, 397, -1, 398, -1, - 401, -1, 402, -1, 404, -1, 406, -1, 407, -1, - 408, -1, 409, -1, 410, -1, 411, -1, 412, -1, - 413, -1, 414, -1, 415, -1, 416, -1, 417, -1, - 418, -1, 419, -1, 421, -1, 425, -1, 426, -1, - 428, -1, 430, -1, 431, -1, 432, -1, 433, -1, - 434, -1, 435, -1, 437, -1, 442, -1, 443, -1, - 445, -1, 448, -1, 449, -1, 451, -1, 452, -1, - 453, -1, 454, -1, 455, -1, 458, -1, 459, -1, - 460, -1, 463, -1, 464, -1, 465, -1, 466, -1, - 468, -1, 469, -1, 470, -1, 471, -1, 472, -1, - 475, -1, 477, -1, 479, -1, 480, -1, 481, -1, - 482, -1, 483, -1, 484, -1, 485, -1, 488, -1, - 491, -1, 492, -1, 493, -1, 494, -1, 495, -1, - 496, -1, 508, -1, 509, -1, 510, -1, 511, -1, - 54, -1, 55, -1, 57, -1, 58, -1, 72, -1, - 73, -1, 80, -1, 84, -1, 113, -1, 116, -1, - 154, -1, 161, -1, 167, -1, 178, -1, 184, -1, - 185, -1, 212, -1, 218, -1, 219, -1, 221, -1, - 250, -1, 273, -1, 275, -1, 279, -1, 286, -1, - 288, -1, 304, -1, 308, -1, 327, -1, 331, -1, - 348, -1, 374, -1, 396, -1, 403, -1, 420, -1, - 422, -1, 438, -1, 439, -1, 444, -1, 446, -1, - 450, -1, 473, -1, 474, -1, 497, -1, 498, -1, - 499, -1, 500, -1, 501, -1, 502, -1, 503, -1, - 504, -1, 505, -1, 506, -1, 507, -1, 43, -1, - 47, -1, 50, -1, 56, -1, 82, -1, 90, -1, - 102, -1, 173, -1, 175, -1, 178, -1, 179, -1, - 196, -1, 211, -1, 224, -1, 225, -1, 227, -1, - 238, -1, 240, -1, 250, -1, 274, -1, 283, -1, - 305, -1, 307, -1, 328, -1, 370, -1, 400, -1, - 420, -1, 429, -1, 478, -1, 38, -1, 43, -1, - 47, -1, 50, -1, 56, -1, 60, -1, 82, -1, - 84, -1, 90, -1, 102, -1, 173, -1, 175, -1, - 179, -1, 196, -1, 211, -1, 224, -1, 225, -1, - 227, -1, 238, -1, 240, -1, 274, -1, 283, -1, - 305, -1, 307, -1, 328, -1, 370, -1, 389, -1, - 400, -1, 429, -1, 450, -1, 461, -1, 478, -1, - 38, -1, 43, -1, 47, -1, 50, -1, 54, -1, - 55, -1, 56, -1, 57, -1, 58, -1, 60, -1, - 73, -1, 72, -1, 80, -1, 82, -1, 84, -1, - 90, -1, 102, -1, 113, -1, 116, -1, 154, -1, - 161, -1, 167, -1, 173, -1, 175, -1, 178, -1, - 179, -1, 184, -1, 185, -1, 196, -1, 211, -1, - 212, -1, 219, -1, 221, -1, 218, -1, 224, -1, - 225, -1, 227, -1, 238, -1, 240, -1, 250, -1, - 273, -1, 274, -1, 275, -1, 279, -1, 283, -1, - 286, -1, 288, -1, 305, -1, 304, -1, 307, -1, - 308, -1, 327, -1, 328, -1, 331, -1, 348, -1, - 370, -1, 374, -1, 389, -1, 396, -1, 400, -1, - 403, -1, 420, -1, 422, -1, 429, -1, 438, -1, - 439, -1, 444, -1, 446, -1, 450, -1, 461, -1, - 473, -1, 474, -1, 478, -1, 497, -1, 498, -1, - 499, -1, 500, -1, 501, -1, 502, -1, 503, -1, - 504, -1, 505, -1, 506, -1, 507, -1, 38, -1, - 43, -1, 47, -1, 50, -1, 56, -1, 60, -1, - 82, -1, 84, -1, 90, -1, 102, -1, 173, -1, + -1, 857, -1, 858, -1, 561, -1, 860, 916, 919, + 920, -1, 860, 916, 919, -1, 324, 860, -1, 861, + 201, 861, -1, -1, 860, 919, 920, -1, 860, 920, + 919, -1, 860, 919, -1, 860, 920, -1, 907, -1, + -1, 174, 860, -1, 169, 860, -1, 860, 174, 908, + -1, 174, 908, -1, 908, -1, 717, -1, 528, 908, + 529, -1, 929, -1, 866, -1, 66, 927, 924, 926, + 144, -1, 925, -1, 924, 925, -1, 486, 860, 436, + 860, -1, 140, 860, -1, -1, 860, -1, -1, 559, + -1, 559, -1, 559, 562, -1, 526, 860, 527, -1, + 526, 930, 19, 930, 527, -1, 526, 930, 19, 930, + 19, 930, 527, -1, 526, 930, 19, 520, 19, 930, + 527, -1, 860, -1, -1, -1, 931, 563, -1, -1, + 528, 529, -1, 528, 910, 529, -1, 530, 564, 932, + -1, 526, 860, 527, -1, 526, 930, 19, 930, 527, + -1, 526, 930, 19, 930, 19, 930, 527, -1, 526, + 930, 19, 520, 19, 930, 527, -1, -1, 934, 933, + -1, 46, -1, -1, 938, -1, -1, 939, -1, 937, + 532, 939, -1, 937, -1, 937, 532, -1, 860, 41, + 968, -1, 860, 3, -1, 860, -1, 559, 19, 860, + -1, 150, 528, 943, 529, -1, 150, 941, -1, 560, + -1, 941, 530, 560, -1, 941, -1, 942, 532, 941, + -1, 942, -1, 942, 532, -1, 940, -1, -1, 860, + 41, 559, -1, 945, -1, 946, 532, 945, -1, 946, + -1, 946, 532, -1, 361, 528, 947, 529, -1, 361, + 945, -1, -1, 941, 41, 559, -1, 949, -1, 950, + 532, 949, -1, 950, -1, 950, 532, -1, 359, 528, + 951, 529, -1, 359, 949, -1, -1, 558, -1, 953, + 532, 558, -1, 957, -1, 954, 532, 957, -1, 954, + -1, 954, 532, -1, 955, -1, 528, 955, 529, -1, + 560, -1, 962, -1, 559, 562, -1, 960, -1, 4, + -1, 561, 931, -1, 6, -1, 7, -1, 958, 561, + -1, 958, 528, 910, 743, 742, 529, 561, -1, 828, + 561, -1, 844, 528, 860, 529, 859, -1, 844, 960, + 859, -1, 844, 561, 859, -1, 447, -1, 162, -1, + 285, -1, 9, -1, 3, -1, 1043, -1, 1048, -1, + 3, -1, 1043, -1, 1045, -1, 3, -1, 1043, -1, + 1046, -1, 559, -1, 559, 965, -1, 530, 564, -1, + 965, 530, 564, -1, 528, 955, 529, -1, -1, 961, + -1, 565, -1, 5, -1, 332, 957, 970, 41, 971, + -1, 528, 912, 529, -1, -1, 716, -1, 568, -1, + 702, -1, 703, -1, 1016, -1, 1032, -1, 101, 379, + 558, 973, -1, 101, 379, 194, 280, 154, 558, 973, + -1, 101, 300, 361, 379, 558, 973, -1, 973, 974, + -1, -1, 622, -1, 975, -1, 594, -1, 1038, -1, + 101, 981, 205, 978, 979, 295, 558, 977, 528, 587, + 529, 980, 817, -1, 101, 981, 205, 978, 194, 280, + 154, 655, 295, 558, 977, 528, 587, 529, 980, 817, + -1, 559, -1, 467, 976, -1, -1, 90, -1, -1, + 655, -1, -1, 490, 637, -1, -1, 457, -1, -1, + 33, 427, 811, 395, 379, 957, -1, 33, 427, 194, + 154, 811, 395, 379, 957, -1, 33, 390, 558, 395, + 379, 957, -1, 33, 390, 194, 154, 558, 395, 379, + 957, -1, 33, 480, 558, 395, 379, 957, -1, 33, + 480, 194, 154, 558, 395, 379, 957, -1, 170, 76, + 984, -1, 76, 984, -1, 559, -1, -1, 85, 295, + 987, 558, 224, 986, -1, 85, 295, 83, 860, 224, + 986, -1, 561, -1, 285, -1, 427, -1, 390, -1, + 176, -1, 249, -1, 249, 427, -1, 480, -1, 109, + -1, 205, -1, 379, -1, 451, -1, 156, 109, 561, + 710, -1, 156, 109, 559, 440, 561, 710, -1, 200, + 109, 561, -1, 155, 993, -1, 155, 997, 991, 993, + -1, 155, 478, 993, -1, 155, 528, 996, 529, 993, + -1, 478, -1, -1, 998, -1, 611, -1, -1, 982, + -1, 608, -1, 542, -1, 1037, -1, 983, -1, 703, + -1, 1040, -1, 691, -1, 972, -1, 594, -1, 622, + -1, 589, -1, 557, -1, 1016, -1, 674, -1, 604, + -1, 975, -1, 568, -1, 1007, -1, 680, -1, 593, + -1, 969, -1, 566, -1, 716, -1, 618, -1, 702, + -1, 603, -1, 1011, -1, 1029, -1, 1001, -1, 1032, + -1, 1038, -1, 3, -1, 1043, -1, 1047, -1, 994, + -1, 561, -1, 999, -1, 996, 532, 999, -1, 36, + -1, 35, -1, 447, -1, 162, -1, 295, -1, 995, + -1, 1000, 992, -1, 994, -1, 997, -1, 395, 1002, + -1, 395, 244, 1002, -1, 395, 394, 1002, -1, 395, + 180, 1002, -1, 395, 475, 1002, -1, 1003, -1, 1036, + 174, 105, -1, 438, 511, 1005, -1, 379, 561, -1, + 1036, 440, 1006, -1, 1036, 517, 1006, -1, 860, -1, + 561, -1, 3, -1, 844, 561, 859, -1, 844, 528, + 960, 529, 561, -1, 611, -1, 118, -1, 244, -1, + 1004, -1, 1006, 532, 1004, -1, 243, 1009, -1, 1008, + 216, 1009, 1010, -1, 1008, 216, 1009, 174, 559, 1010, + -1, 1008, 216, 1009, 174, 561, 1010, -1, -1, 170, + -1, 561, -1, 559, -1, -1, 479, 561, -1, 479, + 559, -1, 468, 1013, 1015, 991, -1, 468, 1013, 1015, + 991, 558, 966, -1, 468, 1013, 1015, 991, 1020, -1, + 468, 528, 1014, 529, -1, 468, 528, 1014, 529, 558, + 966, -1, 997, -1, 478, -1, 173, -1, 175, -1, + 3, -1, 175, -1, -1, 1012, -1, 1014, 532, 1012, + -1, 173, -1, -1, 573, 123, 174, 1017, 1019, 1018, + 579, -1, 448, 737, 1017, -1, 811, -1, 811, 559, + -1, 811, 41, 559, -1, 487, 860, -1, -1, 467, + 792, -1, -1, 997, 991, -1, 997, 991, 558, 966, + -1, 48, 1023, 561, 1024, 1028, -1, 48, 194, 280, + 154, 1023, 561, 1024, 1028, -1, 48, 300, 361, 1023, + 561, 1024, 1028, -1, 129, 565, -1, 129, 109, 565, + -1, 129, 109, 194, 154, 565, -1, 109, -1, -1, + 41, 559, -1, -1, 860, -1, -1, 565, 1025, -1, + 1026, -1, 1027, 532, 1026, -1, 528, 1027, 529, -1, + -1, 363, 1031, -1, 363, 244, 1031, -1, 363, 394, + 1031, -1, 363, 180, 1031, -1, 363, 475, 1031, -1, + 1036, -1, 31, -1, 1030, -1, 438, 511, -1, 442, + 226, 239, -1, 1034, 716, -1, 423, 716, -1, 423, + 558, -1, 1034, 428, 174, 558, -1, 1034, 558, -1, + 1034, 438, 511, -1, 1034, 442, 226, 239, -1, 1034, + 31, 1035, -1, 1034, -1, 128, -1, 127, -1, 399, + -1, 1033, -1, 428, -1, -1, 559, -1, 1036, 530, + 559, -1, 62, 870, -1, 101, 672, 480, 558, 661, + 980, 41, 716, 1039, -1, 101, 672, 480, 194, 280, + 154, 558, 661, 980, 41, 716, 1039, -1, 101, 300, + 361, 672, 480, 558, 661, 980, 41, 716, 1039, -1, + 101, 672, 351, 480, 558, 528, 665, 529, 980, 41, + 716, 1039, -1, 101, 300, 361, 672, 351, 480, 558, + 528, 665, 529, 980, 41, 716, 1039, -1, 490, 75, + 298, -1, 490, 65, 75, 298, -1, 490, 244, 75, + 298, -1, -1, 101, 672, 427, 1042, 41, 716, 1041, + -1, 101, 672, 427, 194, 280, 154, 1042, 41, 716, + 1041, -1, 101, 300, 361, 672, 427, 1042, 41, 716, + 1041, -1, 490, 108, -1, 490, 278, 108, -1, -1, + 558, 661, 644, 646, 636, -1, 23, -1, 24, -1, + 25, -1, 26, -1, 27, -1, 28, -1, 29, -1, + 30, -1, 32, -1, 33, -1, 34, -1, 44, -1, + 45, -1, 48, -1, 49, -1, 51, -1, 52, -1, + 53, -1, 61, -1, 62, -1, 63, -1, 64, -1, + 65, -1, 68, -1, 69, -1, 70, -1, 71, -1, + 74, -1, 76, -1, 77, -1, 78, -1, 79, -1, + 85, -1, 86, -1, 87, -1, 88, -1, 89, -1, + 91, -1, 92, -1, 93, -1, 95, -1, 96, -1, + 97, -1, 98, -1, 99, -1, 100, -1, 103, -1, + 104, -1, 105, -1, 106, -1, 107, -1, 108, -1, + 109, -1, 110, -1, 111, -1, 112, -1, 114, -1, + 115, -1, 117, -1, 119, -1, 121, -1, 122, -1, + 123, -1, 124, -1, 125, -1, 126, -1, 129, -1, + 130, -1, 131, -1, 132, -1, 135, -1, 136, -1, + 137, -1, 138, -1, 139, -1, 141, -1, 142, -1, + 143, -1, 145, -1, 146, -1, 147, -1, 148, -1, + 150, -1, 151, -1, 152, -1, 153, -1, 155, -1, + 156, -1, 157, -1, 158, -1, 159, -1, 160, -1, + 163, -1, 165, -1, 166, -1, 168, -1, 170, -1, + 172, -1, 176, -1, 177, -1, 180, -1, 181, -1, + 182, -1, 186, -1, 187, -1, 189, -1, 190, -1, + 191, -1, 192, -1, 193, -1, 194, -1, 195, -1, + 197, -1, 198, -1, 199, -1, 200, -1, 202, -1, + 203, -1, 204, -1, 205, -1, 206, -1, 207, -1, + 208, -1, 210, -1, 213, -1, 214, -1, 215, -1, + 216, -1, 217, -1, 223, -1, 226, -1, 228, -1, + 229, -1, 230, -1, 232, -1, 233, -1, 234, -1, + 237, -1, 239, -1, 242, -1, 243, -1, 244, -1, + 245, -1, 246, -1, 247, -1, 248, -1, 249, -1, + 251, -1, 252, -1, 253, -1, 254, -1, 255, -1, + 256, -1, 257, -1, 258, -1, 259, -1, 260, -1, + 261, -1, 262, -1, 263, -1, 264, -1, 265, -1, + 266, -1, 267, -1, 268, -1, 269, -1, 270, -1, + 271, -1, 272, -1, 276, -1, 277, -1, 278, -1, + 281, -1, 282, -1, 284, -1, 287, -1, 289, -1, + 290, -1, 291, -1, 293, -1, 294, -1, 297, -1, + 298, -1, 299, -1, 302, -1, 303, -1, 306, -1, + 309, -1, 310, -1, 311, -1, 312, -1, 313, -1, + 314, -1, 315, -1, 316, -1, 317, -1, 318, -1, + 319, -1, 320, -1, 325, -1, 326, -1, 329, -1, + 330, -1, 332, -1, 333, -1, 334, -1, 336, -1, + 337, -1, 338, -1, 339, -1, 340, -1, 341, -1, + 343, -1, 344, -1, 345, -1, 346, -1, 347, -1, + 349, -1, 350, -1, 351, -1, 352, -1, 354, -1, + 355, -1, 356, -1, 357, -1, 358, -1, 359, -1, + 360, -1, 361, -1, 362, -1, 363, -1, 364, -1, + 365, -1, 366, -1, 368, -1, 369, -1, 371, -1, + 372, -1, 373, -1, 375, -1, 376, -1, 377, -1, + 378, -1, 379, -1, 380, -1, 381, -1, 382, -1, + 383, -1, 384, -1, 385, -1, 386, -1, 387, -1, + 390, -1, 391, -1, 392, -1, 393, -1, 394, -1, + 395, -1, 397, -1, 398, -1, 401, -1, 402, -1, + 404, -1, 406, -1, 407, -1, 408, -1, 409, -1, + 410, -1, 411, -1, 412, -1, 413, -1, 414, -1, + 415, -1, 416, -1, 417, -1, 418, -1, 419, -1, + 421, -1, 425, -1, 426, -1, 428, -1, 430, -1, + 431, -1, 432, -1, 433, -1, 434, -1, 435, -1, + 437, -1, 442, -1, 443, -1, 445, -1, 448, -1, + 449, -1, 451, -1, 452, -1, 453, -1, 454, -1, + 455, -1, 458, -1, 459, -1, 460, -1, 463, -1, + 464, -1, 465, -1, 466, -1, 468, -1, 469, -1, + 470, -1, 471, -1, 472, -1, 475, -1, 477, -1, + 479, -1, 480, -1, 481, -1, 482, -1, 483, -1, + 484, -1, 485, -1, 488, -1, 491, -1, 492, -1, + 493, -1, 494, -1, 495, -1, 496, -1, 508, -1, + 509, -1, 510, -1, 511, -1, 54, -1, 55, -1, + 57, -1, 58, -1, 72, -1, 73, -1, 80, -1, + 84, -1, 113, -1, 116, -1, 154, -1, 161, -1, + 167, -1, 178, -1, 184, -1, 185, -1, 212, -1, + 218, -1, 219, -1, 221, -1, 250, -1, 273, -1, + 275, -1, 279, -1, 286, -1, 288, -1, 304, -1, + 308, -1, 327, -1, 331, -1, 348, -1, 374, -1, + 396, -1, 403, -1, 420, -1, 422, -1, 438, -1, + 439, -1, 444, -1, 446, -1, 450, -1, 473, -1, + 474, -1, 497, -1, 498, -1, 499, -1, 500, -1, + 501, -1, 502, -1, 503, -1, 504, -1, 505, -1, + 506, -1, 507, -1, 43, -1, 47, -1, 50, -1, + 56, -1, 82, -1, 90, -1, 102, -1, 173, -1, 175, -1, 178, -1, 179, -1, 196, -1, 211, -1, 224, -1, 225, -1, 227, -1, 238, -1, 240, -1, 250, -1, 274, -1, 283, -1, 305, -1, 307, -1, - 328, -1, 370, -1, 389, -1, 400, -1, 420, -1, - 429, -1, 450, -1, 461, -1, 478, -1, 31, -1, - 35, -1, 36, -1, 37, -1, 39, -1, 40, -1, - 41, -1, 42, -1, 46, -1, 59, -1, 66, -1, - 67, -1, 75, -1, 81, -1, 83, -1, 94, -1, - 101, -1, 118, -1, 120, -1, 127, -1, 128, -1, - 133, -1, 134, -1, 140, -1, 144, -1, 149, -1, - 162, -1, 164, -1, 169, -1, 171, -1, 174, -1, - 183, -1, 188, -1, 201, -1, 209, -1, 220, -1, - 222, -1, 231, -1, 235, -1, 236, -1, 241, -1, - 280, -1, 285, -1, 292, -1, 295, -1, 296, -1, - 300, -1, 301, -1, 321, -1, 322, -1, 323, -1, - 324, -1, 335, -1, 342, -1, 353, -1, 367, -1, - 388, -1, 399, -1, 405, -1, 423, -1, 424, -1, - 427, -1, 436, -1, 440, -1, 441, -1, 447, -1, - 456, -1, 457, -1, 462, -1, 467, -1, 476, -1, - 486, -1, 487, -1, 489, -1, 490, -1 + 328, -1, 370, -1, 400, -1, 420, -1, 429, -1, + 478, -1, 38, -1, 43, -1, 47, -1, 50, -1, + 56, -1, 60, -1, 82, -1, 84, -1, 90, -1, + 102, -1, 173, -1, 175, -1, 179, -1, 196, -1, + 211, -1, 224, -1, 225, -1, 227, -1, 238, -1, + 240, -1, 274, -1, 283, -1, 305, -1, 307, -1, + 328, -1, 370, -1, 389, -1, 400, -1, 429, -1, + 450, -1, 461, -1, 478, -1, 38, -1, 43, -1, + 47, -1, 50, -1, 54, -1, 55, -1, 56, -1, + 57, -1, 58, -1, 60, -1, 73, -1, 72, -1, + 80, -1, 82, -1, 84, -1, 90, -1, 102, -1, + 113, -1, 116, -1, 154, -1, 161, -1, 167, -1, + 173, -1, 175, -1, 178, -1, 179, -1, 184, -1, + 185, -1, 196, -1, 211, -1, 212, -1, 219, -1, + 221, -1, 218, -1, 224, -1, 225, -1, 227, -1, + 238, -1, 240, -1, 250, -1, 273, -1, 274, -1, + 275, -1, 279, -1, 283, -1, 286, -1, 288, -1, + 305, -1, 304, -1, 307, -1, 308, -1, 327, -1, + 328, -1, 331, -1, 348, -1, 370, -1, 374, -1, + 389, -1, 396, -1, 400, -1, 403, -1, 420, -1, + 422, -1, 429, -1, 438, -1, 439, -1, 444, -1, + 446, -1, 450, -1, 461, -1, 473, -1, 474, -1, + 478, -1, 497, -1, 498, -1, 499, -1, 500, -1, + 501, -1, 502, -1, 503, -1, 504, -1, 505, -1, + 506, -1, 507, -1, 38, -1, 43, -1, 47, -1, + 50, -1, 56, -1, 60, -1, 82, -1, 84, -1, + 90, -1, 102, -1, 173, -1, 175, -1, 178, -1, + 179, -1, 196, -1, 211, -1, 224, -1, 225, -1, + 227, -1, 238, -1, 240, -1, 250, -1, 274, -1, + 283, -1, 305, -1, 307, -1, 328, -1, 370, -1, + 389, -1, 400, -1, 420, -1, 429, -1, 450, -1, + 461, -1, 478, -1, 31, -1, 35, -1, 36, -1, + 37, -1, 39, -1, 40, -1, 41, -1, 42, -1, + 46, -1, 59, -1, 66, -1, 67, -1, 75, -1, + 81, -1, 83, -1, 94, -1, 101, -1, 118, -1, + 120, -1, 127, -1, 128, -1, 133, -1, 134, -1, + 140, -1, 144, -1, 149, -1, 162, -1, 164, -1, + 169, -1, 171, -1, 174, -1, 183, -1, 188, -1, + 201, -1, 209, -1, 220, -1, 222, -1, 231, -1, + 235, -1, 236, -1, 241, -1, 280, -1, 285, -1, + 292, -1, 295, -1, 296, -1, 300, -1, 301, -1, + 321, -1, 322, -1, 323, -1, 324, -1, 335, -1, + 342, -1, 353, -1, 367, -1, 388, -1, 399, -1, + 405, -1, 423, -1, 424, -1, 427, -1, 436, -1, + 440, -1, 441, -1, 447, -1, 456, -1, 457, -1, + 462, -1, 467, -1, 476, -1, 486, -1, 487, -1, + 489, -1, 490, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 522, 522, 538, 550, 559, 560, 561, 562, 563, - 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, - 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, - 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, - 594, 595, 596, 597, 598, 599, 600, 601, 603, 9, + 0, 524, 524, 540, 552, 561, 562, 563, 564, 565, + 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, + 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, + 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, + 596, 597, 598, 599, 600, 601, 602, 603, 605, 9, 18, 27, 36, 45, 54, 63, 72, 85, 87, 93, 94, 99, 103, 107, 118, 126, 130, 138, 139, 143, 150, 151, 156, 163, 173, 182, 191, 200, 209, 217, @@ -2699,116 +2705,117 @@ static const yytype_uint16 yyrline[] = 76, 80, 84, 88, 92, 97, 101, 105, 112, 113, 117, 118, 119, 7, 16, 7, 16, 28, 29, 2, 10, 17, 24, 32, 40, 51, 52, 53, 57, 58, - 59, 2, 7, 21, 36, 56, 57, 84, 85, 86, - 87, 88, 89, 93, 94, 99, 104, 105, 106, 107, - 108, 113, 120, 121, 122, 139, 146, 153, 163, 173, - 185, 193, 202, 220, 221, 225, 226, 230, 239, 262, - 276, 283, 288, 290, 292, 294, 297, 300, 301, 302, - 303, 308, 312, 313, 318, 325, 330, 331, 332, 333, - 334, 335, 336, 337, 343, 344, 348, 353, 360, 367, - 374, 386, 387, 388, 389, 393, 398, 399, 400, 405, - 410, 411, 412, 413, 414, 415, 420, 440, 466, 474, - 484, 485, 489, 493, 494, 495, 499, 503, 511, 512, - 517, 518, 519, 523, 531, 532, 537, 538, 542, 547, - 551, 555, 560, 568, 569, 573, 574, 578, 579, 585, - 596, 609, 623, 637, 651, 665, 688, 692, 699, 703, - 711, 716, 723, 733, 734, 735, 736, 737, 744, 751, - 752, 757, 758, 9, 19, 29, 39, 49, 59, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 95, 96, 97, - 98, 99, 100, 105, 106, 111, 112, 113, 118, 119, - 120, 7, 29, 30, 34, 35, 39, 39, 43, 51, - 58, 65, 71, 80, 87, 95, 101, 111, 112, 116, - 126, 127, 128, 132, 142, 142, 146, 147, 7, 16, - 25, 34, 43, 52, 64, 74, 84, 88, 95, 99, - 103, 113, 117, 124, 125, 130, 134, 138, 145, 149, - 156, 164, 172, 7, 1, 30, 49, 61, 62, 63, - 67, 68, 73, 77, 94, 95, 99, 100, 105, 106, - 110, 111, 115, 119, 124, 125, 130, 134, 139, 143, - 147, 151, 155, 159, 163, 167, 171, 175, 179, 183, - 187, 191, 195, 199, 211, 212, 213, 214, 215, 216, - 217, 47, 48, 52, 53, 54, 72, 73, 80, 88, - 96, 104, 112, 120, 131, 132, 159, 164, 172, 188, - 205, 223, 241, 242, 261, 265, 269, 273, 277, 287, - 298, 308, 317, 328, 339, 351, 366, 384, 384, 388, - 388, 392, 392, 396, 402, 409, 413, 414, 418, 419, - 433, 440, 447, 457, 458, 461, 475, 476, 480, 481, - 485, 486, 490, 491, 492, 496, 507, 515, 520, 525, - 530, 535, 543, 551, 556, 561, 568, 569, 573, 574, - 575, 579, 586, 587, 591, 592, 596, 597, 598, 602, - 603, 607, 608, 624, 625, 628, 637, 648, 649, 650, - 653, 654, 655, 659, 660, 661, 662, 666, 667, 671, - 673, 689, 691, 696, 699, 704, 708, 712, 719, 723, - 727, 731, 738, 743, 750, 751, 755, 760, 764, 768, - 776, 783, 784, 789, 790, 795, 796, 800, 810, 811, - 816, 817, 822, 824, 826, 831, 851, 852, 854, 859, - 860, 864, 865, 868, 869, 894, 895, 900, 904, 905, - 909, 910, 914, 915, 916, 917, 918, 922, 935, 942, - 949, 956, 957, 961, 962, 966, 967, 971, 972, 976, - 977, 981, 982, 986, 997, 998, 999, 1000, 1004, 1005, - 1010, 1011, 1012, 1021, 1027, 1036, 1037, 1050, 1051, 1055, - 1056, 1060, 1061, 1065, 1076, 1083, 1090, 1098, 1106, 1116, - 1124, 1133, 1142, 1151, 1155, 1160, 1165, 1176, 1190, 1191, - 1194, 1195, 1196, 1199, 1207, 1217, 1218, 1219, 1222, 1230, - 1239, 1243, 1250, 1251, 1255, 1264, 1268, 1293, 1297, 1310, - 1324, 1339, 1351, 1364, 1378, 1392, 1405, 1420, 1439, 1445, - 1450, 1456, 1463, 1464, 1472, 1476, 1480, 1486, 1493, 1498, - 1499, 1500, 1501, 1502, 1503, 1507, 1508, 1520, 1521, 1526, - 1533, 1540, 1547, 1579, 1590, 1603, 1608, 1609, 1612, 1613, - 1616, 1617, 1622, 1623, 1628, 1632, 1638, 1659, 1667, 1681, - 1684, 1688, 1688, 1691, 1692, 1694, 1699, 1706, 1711, 1717, - 1722, 1728, 1733, 1740, 1747, 1757, 1758, 1762, 1764, 1767, - 1771, 1772, 1773, 1774, 1775, 1776, 1781, 1801, 1802, 1803, - 1804, 1815, 1829, 1830, 1836, 1841, 1846, 1851, 1856, 1861, - 1866, 1871, 1877, 1883, 1889, 1896, 1918, 1927, 1931, 1939, - 1943, 1951, 1963, 1984, 1988, 1994, 1998, 2011, 2019, 2029, - 2031, 2033, 2035, 2037, 2039, 2044, 2045, 2052, 2061, 2069, - 2078, 2089, 2097, 2098, 2099, 2103, 2103, 2106, 2106, 2109, - 2109, 2112, 2112, 2115, 2115, 2118, 2118, 2121, 2121, 2124, - 2124, 2127, 2127, 2130, 2130, 2133, 2133, 2136, 2136, 2139, - 2139, 2142, 2144, 2146, 2148, 2150, 2152, 2154, 2156, 2158, - 2160, 2162, 2164, 2166, 2168, 2173, 2178, 2184, 2191, 2196, - 2202, 2208, 2239, 2241, 2243, 2251, 2266, 2268, 2270, 2272, - 2274, 2276, 2278, 2280, 2282, 2284, 2286, 2288, 2290, 2292, - 2294, 2296, 2299, 2301, 2303, 2306, 2308, 2310, 2312, 2314, - 2319, 2324, 2331, 2336, 2343, 2348, 2355, 2360, 2368, 2376, - 2384, 2392, 2410, 2418, 2426, 2434, 2442, 2450, 2458, 2466, - 2470, 2486, 2494, 2502, 2510, 2518, 2526, 2534, 2538, 2542, - 2546, 2550, 2558, 2566, 2574, 2582, 2602, 2624, 2635, 2642, - 2656, 2664, 2669, 2679, 2688, 2709, 2711, 2713, 2715, 2717, - 2719, 2721, 2723, 2725, 2727, 2729, 2731, 2733, 2735, 2737, - 2739, 2741, 2743, 2745, 2747, 2749, 2751, 2755, 2759, 2763, - 2777, 2778, 2792, 2793, 2794, 2805, 2829, 2840, 2850, 2854, - 2858, 2865, 2869, 2876, 2883, 2884, 2885, 2886, 2887, 2888, - 2889, 2890, 2901, 2906, 2915, 2921, 2928, 2948, 2952, 2959, - 2966, 2974, 2982, 2993, 3013, 3049, 3060, 3061, 3068, 3074, - 3076, 3078, 3082, 3091, 3096, 3103, 3118, 3125, 3129, 3133, - 3137, 3141, 3151, 3160, 3182, 3183, 3187, 3188, 3189, 3193, - 3194, 3201, 3202, 3206, 3207, 3212, 3220, 3222, 3236, 3239, - 3266, 3267, 3270, 3271, 3279, 3287, 3295, 3304, 3314, 3332, - 3378, 3387, 3396, 3405, 3414, 3426, 3427, 3428, 3429, 3430, - 3444, 3445, 3448, 3449, 3453, 3463, 3464, 3468, 3469, 3473, - 3480, 3481, 3486, 3487, 3492, 3493, 3496, 3497, 3498, 3501, - 3502, 3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, - 3514, 3515, 3516, 3517, 3518, 3521, 3523, 3528, 3530, 3535, - 3537, 3539, 3541, 3543, 3545, 3547, 3549, 3563, 3565, 3570, - 3574, 3581, 3586, 3592, 3596, 3603, 3608, 3615, 3620, 3628, - 3632, 3638, 3642, 3651, 3662, 3663, 3667, 3671, 3678, 3679, - 3680, 3681, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, - 3690, 3691, 3692, 3702, 3706, 3713, 3720, 3721, 3737, 3741, - 3746, 3750, 3765, 3770, 3774, 3777, 3780, 3781, 3782, 3785, - 3792, 3793, 3794, 3804, 3818, 3819, 3823, 3834, 3835, 3838, - 3839, 3847, 3853, 3857, 3864, 3872, 3880, 3888, 3898, 3899, - 3904, 3905, 3909, 3910, 3911, 3915, 3924, 3932, 3940, 3949, - 3964, 3965, 3970, 3971, 3981, 3982, 3986, 3987, 3991, 3992, - 3995, 4011, 4019, 4027, 4037, 4038, 4042, 4046, 4052, 4054, - 4059, 4060, 4064, 4065, 4068, 4072, 4073, 4077, 4078, 4081, - 4082, 4083, 4086, 4090, 4091, 4095, 4096, 4098, 4099, 4100, - 4110, 4111, 4115, 4117, 4123, 4124, 4128, 4129, 4132, 4143, - 4146, 4157, 4161, 4165, 4177, 4181, 4190, 4197, 4235, 4239, - 4243, 4247, 4251, 4255, 4259, 4265, 4282, 4283, 4284, 4287, - 4288, 4289, 4292, 4293, 4294, 4297, 4298, 4301, 4303, 4308, - 4309, 4312, 4316, 4317, 7, 18, 19, 23, 24, 25, + 59, 2, 7, 31, 56, 86, 87, 114, 115, 116, + 117, 118, 119, 123, 124, 128, 133, 134, 135, 136, + 137, 142, 149, 150, 151, 168, 175, 182, 192, 202, + 214, 222, 231, 249, 250, 254, 255, 259, 268, 291, + 305, 312, 317, 319, 321, 323, 326, 329, 330, 331, + 332, 337, 340, 341, 346, 353, 358, 359, 360, 361, + 362, 363, 364, 365, 371, 372, 375, 380, 387, 394, + 401, 412, 413, 417, 421, 428, 429, 430, 431, 434, + 439, 440, 441, 446, 451, 452, 453, 454, 455, 456, + 461, 481, 507, 515, 525, 526, 530, 534, 535, 536, + 540, 544, 552, 553, 558, 559, 560, 564, 572, 573, + 578, 579, 583, 588, 592, 596, 601, 605, 609, 616, + 617, 621, 622, 626, 627, 633, 644, 657, 671, 685, + 699, 713, 736, 740, 747, 751, 759, 764, 771, 781, + 782, 783, 784, 785, 792, 799, 800, 804, 805, 9, + 19, 29, 39, 49, 59, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 95, 96, 97, 98, 99, 100, 105, + 106, 111, 112, 113, 118, 119, 120, 7, 29, 30, + 34, 35, 39, 39, 43, 51, 58, 65, 71, 80, + 87, 95, 101, 111, 112, 116, 126, 127, 128, 132, + 142, 142, 146, 147, 7, 16, 25, 34, 43, 52, + 64, 74, 84, 88, 95, 99, 103, 113, 117, 124, + 125, 130, 134, 138, 145, 149, 156, 164, 172, 7, + 1, 30, 49, 61, 62, 63, 67, 68, 73, 77, + 94, 95, 99, 100, 105, 106, 110, 111, 115, 119, + 124, 125, 130, 134, 139, 143, 147, 151, 155, 159, + 163, 167, 171, 175, 179, 183, 187, 191, 195, 199, + 211, 212, 213, 214, 215, 216, 217, 47, 48, 52, + 53, 54, 72, 73, 80, 88, 96, 104, 112, 120, + 131, 132, 159, 164, 172, 188, 205, 223, 241, 242, + 261, 265, 269, 273, 277, 287, 298, 308, 317, 328, + 339, 351, 366, 384, 384, 388, 388, 392, 392, 396, + 402, 409, 413, 414, 418, 419, 433, 440, 447, 457, + 458, 461, 475, 476, 480, 481, 485, 486, 490, 491, + 492, 496, 507, 515, 520, 525, 530, 535, 543, 551, + 556, 561, 568, 569, 573, 574, 575, 579, 586, 587, + 591, 592, 596, 597, 598, 602, 603, 607, 608, 624, + 625, 628, 637, 648, 649, 650, 653, 654, 655, 659, + 660, 661, 662, 666, 667, 671, 673, 689, 691, 696, + 699, 704, 708, 712, 719, 723, 727, 731, 738, 743, + 750, 751, 755, 760, 764, 768, 776, 783, 784, 789, + 790, 795, 796, 800, 810, 811, 816, 817, 822, 824, + 826, 831, 851, 852, 854, 859, 860, 864, 865, 868, + 869, 894, 895, 900, 904, 905, 909, 910, 914, 915, + 916, 917, 918, 922, 935, 942, 949, 956, 957, 961, + 962, 966, 967, 971, 972, 976, 977, 981, 982, 986, + 997, 998, 999, 1000, 1004, 1005, 1010, 1011, 1012, 1021, + 1027, 1036, 1037, 1050, 1051, 1055, 1056, 1060, 1061, 1065, + 1076, 1083, 1090, 1098, 1106, 1116, 1124, 1133, 1142, 1151, + 1155, 1160, 1165, 1176, 1190, 1191, 1194, 1195, 1196, 1199, + 1207, 1217, 1218, 1219, 1222, 1230, 1239, 1243, 1250, 1251, + 1255, 1264, 1268, 1293, 1297, 1310, 1324, 1339, 1351, 1364, + 1378, 1392, 1405, 1420, 1439, 1445, 1450, 1456, 1463, 1464, + 1472, 1476, 1480, 1486, 1493, 1498, 1499, 1500, 1501, 1502, + 1503, 1507, 1508, 1520, 1521, 1526, 1533, 1540, 1547, 1579, + 1590, 1603, 1608, 1609, 1612, 1613, 1616, 1617, 1622, 1623, + 1628, 1632, 1638, 1659, 1667, 1681, 1684, 1688, 1688, 1691, + 1692, 1694, 1699, 1706, 1711, 1716, 1722, 1728, 1733, 1738, + 1744, 1750, 1755, 1762, 1769, 1779, 1780, 1784, 1786, 1789, + 1793, 1794, 1795, 1796, 1797, 1798, 1803, 1823, 1824, 1825, + 1826, 1837, 1851, 1852, 1858, 1863, 1868, 1873, 1878, 1883, + 1888, 1893, 1899, 1905, 1911, 1918, 1940, 1949, 1953, 1961, + 1965, 1973, 1985, 2006, 2010, 2016, 2020, 2033, 2041, 2051, + 2053, 2055, 2057, 2059, 2061, 2066, 2067, 2074, 2083, 2091, + 2100, 2111, 2119, 2120, 2121, 2125, 2125, 2128, 2128, 2131, + 2131, 2134, 2134, 2137, 2137, 2140, 2140, 2143, 2143, 2146, + 2146, 2149, 2149, 2152, 2152, 2155, 2155, 2158, 2158, 2161, + 2161, 2164, 2166, 2168, 2170, 2172, 2174, 2176, 2178, 2180, + 2182, 2184, 2186, 2188, 2190, 2195, 2200, 2206, 2213, 2218, + 2224, 2230, 2261, 2263, 2265, 2273, 2288, 2290, 2292, 2294, + 2296, 2298, 2300, 2302, 2304, 2306, 2308, 2310, 2312, 2314, + 2316, 2318, 2321, 2323, 2325, 2328, 2330, 2332, 2334, 2336, + 2341, 2346, 2353, 2358, 2365, 2370, 2377, 2382, 2390, 2398, + 2406, 2414, 2432, 2440, 2448, 2456, 2464, 2472, 2480, 2488, + 2492, 2508, 2516, 2524, 2532, 2540, 2548, 2556, 2560, 2564, + 2568, 2572, 2580, 2588, 2596, 2604, 2624, 2646, 2657, 2664, + 2678, 2686, 2691, 2701, 2710, 2731, 2733, 2735, 2737, 2739, + 2741, 2743, 2745, 2747, 2749, 2751, 2753, 2755, 2757, 2759, + 2761, 2763, 2765, 2767, 2769, 2771, 2773, 2777, 2781, 2785, + 2799, 2800, 2814, 2815, 2816, 2827, 2851, 2862, 2872, 2876, + 2880, 2887, 2891, 2898, 2905, 2906, 2907, 2908, 2909, 2910, + 2911, 2912, 2923, 2928, 2937, 2943, 2950, 2970, 2974, 2981, + 2988, 2996, 3004, 3015, 3035, 3071, 3082, 3083, 3090, 3096, + 3098, 3100, 3104, 3113, 3118, 3125, 3140, 3147, 3151, 3155, + 3159, 3163, 3173, 3182, 3242, 3243, 3247, 3248, 3249, 3253, + 3254, 3261, 3262, 3266, 3267, 3272, 3280, 3282, 3296, 3299, + 3326, 3327, 3330, 3331, 3339, 3347, 3355, 3364, 3374, 3392, + 3438, 3447, 3456, 3465, 3474, 3486, 3487, 3488, 3489, 3490, + 3504, 3505, 3508, 3509, 3513, 3523, 3524, 3528, 3529, 3533, + 3540, 3541, 3546, 3547, 3552, 3553, 3556, 3557, 3558, 3561, + 3562, 3565, 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, + 3574, 3575, 3576, 3577, 3578, 3581, 3583, 3588, 3590, 3595, + 3597, 3599, 3601, 3603, 3605, 3607, 3609, 3623, 3625, 3630, + 3634, 3641, 3646, 3652, 3656, 3663, 3668, 3675, 3680, 3688, + 3692, 3698, 3702, 3711, 3722, 3723, 3727, 3731, 3738, 3739, + 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, 3748, 3749, + 3750, 3751, 3752, 3762, 3766, 3773, 3780, 3781, 3797, 3801, + 3806, 3810, 3825, 3830, 3834, 3837, 3840, 3841, 3842, 3845, + 3852, 3853, 3854, 3864, 3878, 3879, 3883, 3894, 3895, 3898, + 3899, 3907, 3913, 3917, 3924, 3932, 3940, 3948, 3958, 3959, + 3964, 3965, 3969, 3970, 3971, 3975, 3984, 3992, 4000, 4009, + 4024, 4025, 4030, 4031, 4041, 4042, 4046, 4047, 4051, 4052, + 4055, 4071, 4079, 4087, 4097, 4098, 4102, 4106, 4112, 4114, + 4119, 4120, 4124, 4125, 4128, 4132, 4133, 4137, 4138, 4141, + 4142, 4143, 4146, 4150, 4151, 4155, 4156, 4158, 4159, 4160, + 4170, 4171, 4175, 4177, 4183, 4184, 4188, 4189, 4192, 4203, + 4206, 4217, 4221, 4225, 4237, 4241, 4250, 4257, 4295, 4299, + 4303, 4307, 4311, 4315, 4319, 4325, 4342, 4343, 4344, 4347, + 4348, 4349, 4352, 4353, 4354, 4357, 4358, 4361, 4363, 4368, + 4369, 4372, 4376, 4377, 7, 18, 19, 23, 24, 25, 26, 27, 28, 7, 26, 50, 73, 80, 85, 86, 87, 88, 8, 33, 62, 66, 67, 72, 73, 78, 79, 83, 84, 89, 90, 7, 16, 25, 34, 43, @@ -2831,71 +2838,71 @@ static const yytype_uint16 yyrline[] = 31, 38, 48, 49, 56, 3, 10, 17, 24, 32, 39, 46, 53, 60, 69, 69, 71, 71, 73, 73, 75, 76, 6, 8, 21, 34, 47, 65, 87, 88, - 89, 90, 11, 24, 37, 54, 55, 56, 61, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, - 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, - 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, - 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80 + 89, 90, 11, 24, 37, 54, 55, 56, 61, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89 }; #endif @@ -3020,20 +3027,22 @@ static const char *const yytname[] = "GeneratedConstraintElem", "generic_option_elem", "key_update", "key_actions", "OnCommitOption", "reloptions", "opt_no_inherit", "TableConstraint", "TableLikeOption", "reloption_list", "ExistingIndex", - "ConstraintAttr", "OptWith", "definition", "TableLikeOptionList", - "generic_option_name", "ConstraintAttributeElem", "regularColumnDef", - "generatedColumnDef", "columnDef", "def_list", "index_name", - "TableElement", "def_elem", "opt_definition", "OptTableElementList", - "columnElem", "opt_column_list", "ColQualList", "key_delete", - "reloption_elem", "columnList", "columnList_opt_comma", "func_type", - "ConstraintElem", "TableElementList", "key_match", "TableLikeClause", - "OptTemp", "generated_when", "DropStmt", "drop_type_any_name", - "drop_type_name", "any_name_list", "opt_drop_behavior", - "drop_type_name_on_any_name", "MergeIntoStmt", "opt_and_clause", - "opt_insert_column_list", "opt_star_expr", "matched_clause_action", - "opt_error_message", "matched_clause", "opt_source_or_target", - "not_matched_clause", "matched_or_not_matched_clause", - "merge_match_list", "CreateFunctionStmt", "table_macro_definition", + "ConstraintAttr", "OptPartitionSortedOptions", + "OptPartitionSortedOption", "OptWith", "definition", + "TableLikeOptionList", "generic_option_name", "ConstraintAttributeElem", + "regularColumnDef", "generatedColumnDef", "columnDef", "def_list", + "index_name", "TableElement", "def_elem", "opt_definition", + "OptTableElementList", "columnElem", "opt_column_list", "ColQualList", + "key_delete", "reloption_elem", "columnList", "columnList_opt_comma", + "func_type", "ConstraintElem", "TableElementList", "key_match", + "TableLikeClause", "OptTemp", "generated_when", "DropStmt", + "drop_type_any_name", "drop_type_name", "any_name_list", + "opt_drop_behavior", "drop_type_name_on_any_name", "MergeIntoStmt", + "opt_and_clause", "opt_insert_column_list", "opt_star_expr", + "matched_clause_action", "opt_error_message", "matched_clause", + "opt_source_or_target", "not_matched_clause", + "matched_or_not_matched_clause", "merge_match_list", + "CreateFunctionStmt", "table_macro_definition", "table_macro_definition_parens", "table_macro_list_internal", "table_macro_list", "macro_definition", "macro_definition_list", "macro_alias", "param_list", "MacroParameterList", "MacroParameter", @@ -3239,196 +3248,197 @@ static const yytype_uint16 yyr1[] = 633, 634, 635, 635, 635, 635, 635, 636, 636, 636, 636, 637, 638, 638, 639, 639, 640, 640, 640, 640, 640, 640, 640, 640, 641, 641, 642, 643, 643, 643, - 643, 644, 644, 644, 644, 645, 646, 646, 646, 647, - 648, 648, 648, 648, 648, 648, 649, 650, 651, 651, - 652, 652, 653, 654, 654, 654, 655, 655, 656, 656, - 657, 657, 657, 658, 659, 659, 660, 660, 661, 662, - 662, 662, 662, 663, 663, 664, 664, 665, 665, 665, - 666, 666, 666, 666, 666, 666, 667, 667, 668, 668, - 668, 668, 669, 670, 670, 670, 670, 670, 670, 670, - 670, 671, 671, 672, 672, 672, 672, 672, 672, 673, - 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, - 673, 673, 673, 673, 673, 673, 673, 674, 674, 674, - 674, 674, 674, 675, 675, 676, 676, 676, 677, 677, - 677, 678, 679, 679, 680, 680, 681, 681, 682, 682, - 682, 682, 682, 682, 682, 682, 682, 683, 683, 684, - 685, 685, 685, 686, 687, 687, 688, 688, 689, 689, - 689, 689, 689, 689, 690, 691, 692, 692, 693, 693, - 694, 695, 695, 696, 696, 697, 697, 697, 698, 698, - 699, 699, 699, 700, 701, 701, 701, 702, 702, 702, - 703, 703, 704, 704, 705, 705, 706, 706, 707, 707, - 708, 708, 709, 709, 710, 710, 711, 711, 712, 712, - 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, - 712, 712, 712, 712, 713, 713, 713, 713, 713, 713, - 713, 714, 714, 715, 715, 715, 716, 716, 716, 716, - 716, 716, 716, 716, 717, 717, 718, 718, 719, 719, - 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, - 719, 719, 719, 719, 719, 719, 719, 720, 720, 721, - 721, 722, 722, 723, 723, 723, 724, 724, 725, 725, - 726, 726, 726, 727, 727, 728, 729, 729, 730, 730, - 731, 731, 732, 732, 732, 733, 733, 734, 734, 734, - 734, 734, 734, 734, 734, 734, 735, 735, 736, 736, - 736, 737, 738, 738, 739, 739, 740, 740, 740, 741, - 741, 742, 742, 743, 743, 744, 744, 745, 745, 745, - 746, 746, 746, 747, 747, 747, 747, 748, 748, 749, - 749, 749, 749, 750, 750, 751, 751, 751, 752, 752, - 752, 752, 753, 753, 754, 754, 755, 755, 755, 755, - 756, 757, 757, 758, 758, 759, 759, 760, 761, 761, - 762, 762, 762, 762, 762, 763, 764, 764, 764, 765, - 765, 766, 766, 767, 767, 768, 768, 768, 769, 769, - 770, 770, 771, 771, 771, 771, 771, 772, 773, 774, - 775, 776, 776, 777, 777, 778, 778, 779, 779, 780, - 780, 781, 781, 782, 783, 783, 783, 783, 784, 784, - 785, 785, 785, 786, 786, 787, 787, 788, 788, 789, - 789, 790, 790, 791, 792, 792, 792, 792, 792, 792, - 792, 792, 792, 792, 792, 792, 792, 792, 793, 793, - 794, 794, 794, 795, 795, 796, 796, 796, 797, 797, - 798, 798, 799, 799, 800, 801, 801, 802, 802, 802, - 802, 802, 802, 802, 802, 802, 802, 802, 803, 803, - 803, 803, 804, 804, 805, 805, 805, 805, 805, 806, - 806, 806, 806, 806, 806, 807, 807, 808, 808, 809, - 809, 809, 809, 810, 810, 811, 812, 812, 813, 813, - 814, 814, 815, 815, 816, 816, 817, 818, 818, 819, - 819, 820, 820, 821, 821, 822, 822, 822, 822, 822, - 822, 822, 822, 822, 822, 823, 823, 824, 824, 824, - 825, 825, 825, 825, 825, 825, 825, 826, 826, 826, - 826, 827, 828, 828, 829, 829, 829, 829, 829, 829, - 829, 829, 829, 829, 829, 830, 830, 831, 831, 832, - 832, 833, 834, 835, 835, 836, 836, 837, 838, 839, - 839, 839, 839, 839, 839, 840, 840, 841, 841, 841, - 841, 842, 843, 843, 843, 844, 844, 845, 845, 846, - 846, 847, 847, 848, 848, 849, 849, 850, 850, 851, - 851, 852, 852, 853, 853, 854, 854, 855, 855, 856, - 856, 857, 857, 857, 857, 857, 857, 857, 857, 857, - 857, 857, 857, 857, 857, 857, 857, 857, 857, 857, - 857, 857, 858, 858, 858, 858, 858, 858, 858, 858, - 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, - 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, - 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, - 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, - 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, - 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, - 858, 858, 858, 858, 858, 859, 859, 859, 859, 859, - 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, + 643, 644, 644, 645, 645, 646, 646, 646, 646, 647, + 648, 648, 648, 649, 650, 650, 650, 650, 650, 650, + 651, 652, 653, 653, 654, 654, 655, 656, 656, 656, + 657, 657, 658, 658, 659, 659, 659, 660, 661, 661, + 662, 662, 663, 664, 664, 664, 664, 664, 664, 665, + 665, 666, 666, 667, 667, 667, 668, 668, 668, 668, + 668, 668, 669, 669, 670, 670, 670, 670, 671, 672, + 672, 672, 672, 672, 672, 672, 672, 673, 673, 674, + 674, 674, 674, 674, 674, 675, 675, 675, 675, 675, + 675, 675, 675, 675, 675, 675, 675, 675, 675, 675, + 675, 675, 675, 676, 676, 676, 676, 676, 676, 677, + 677, 678, 678, 678, 679, 679, 679, 680, 681, 681, + 682, 682, 683, 683, 684, 684, 684, 684, 684, 684, + 684, 684, 684, 685, 685, 686, 687, 687, 687, 688, + 689, 689, 690, 690, 691, 691, 691, 691, 691, 691, + 692, 693, 694, 694, 695, 695, 696, 697, 697, 698, + 698, 699, 699, 699, 700, 700, 701, 701, 701, 702, + 703, 703, 703, 704, 704, 704, 705, 705, 706, 706, + 707, 707, 708, 708, 709, 709, 710, 710, 711, 711, + 712, 712, 713, 713, 714, 714, 714, 714, 714, 714, + 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, + 715, 715, 715, 715, 715, 715, 715, 716, 716, 717, + 717, 717, 718, 718, 718, 718, 718, 718, 718, 718, + 719, 719, 720, 720, 721, 721, 721, 721, 721, 721, + 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, + 721, 721, 721, 722, 722, 723, 723, 724, 724, 725, + 725, 725, 726, 726, 727, 727, 728, 728, 728, 729, + 729, 730, 731, 731, 732, 732, 733, 733, 734, 734, + 734, 735, 735, 736, 736, 736, 736, 736, 736, 736, + 736, 736, 737, 737, 738, 738, 738, 739, 740, 740, + 741, 741, 742, 742, 742, 743, 743, 744, 744, 745, + 745, 746, 746, 747, 747, 747, 748, 748, 748, 749, + 749, 749, 749, 750, 750, 751, 751, 751, 751, 752, + 752, 753, 753, 753, 754, 754, 754, 754, 755, 755, + 756, 756, 757, 757, 757, 757, 758, 759, 759, 760, + 760, 761, 761, 762, 763, 763, 764, 764, 764, 764, + 764, 765, 766, 766, 766, 767, 767, 768, 768, 769, + 769, 770, 770, 770, 771, 771, 772, 772, 773, 773, + 773, 773, 773, 774, 775, 776, 777, 778, 778, 779, + 779, 780, 780, 781, 781, 782, 782, 783, 783, 784, + 785, 785, 785, 785, 786, 786, 787, 787, 787, 788, + 788, 789, 789, 790, 790, 791, 791, 792, 792, 793, + 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, + 794, 794, 794, 794, 795, 795, 796, 796, 796, 797, + 797, 798, 798, 798, 799, 799, 800, 800, 801, 801, + 802, 803, 803, 804, 804, 804, 804, 804, 804, 804, + 804, 804, 804, 804, 805, 805, 805, 805, 806, 806, + 807, 807, 807, 807, 807, 808, 808, 808, 808, 808, + 808, 809, 809, 810, 810, 811, 811, 811, 811, 812, + 812, 813, 814, 814, 815, 815, 816, 816, 817, 817, + 818, 818, 819, 820, 820, 821, 821, 822, 822, 823, + 823, 824, 824, 824, 824, 824, 824, 824, 824, 824, + 824, 824, 824, 824, 824, 825, 825, 826, 826, 826, + 827, 827, 827, 827, 827, 827, 827, 828, 828, 828, + 828, 829, 830, 830, 831, 831, 831, 831, 831, 831, + 831, 831, 831, 831, 831, 832, 832, 833, 833, 834, + 834, 835, 836, 837, 837, 838, 838, 839, 840, 841, + 841, 841, 841, 841, 841, 842, 842, 843, 843, 843, + 843, 844, 845, 845, 845, 846, 846, 847, 847, 848, + 848, 849, 849, 850, 850, 851, 851, 852, 852, 853, + 853, 854, 854, 855, 855, 856, 856, 857, 857, 858, + 858, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, 859, - 860, 860, 861, 861, 861, 861, 861, 861, 862, 862, - 862, 863, 863, 863, 864, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 865, 866, 867, 868, 868, 868, - 868, 868, 868, 868, 869, 869, 870, 870, 871, 871, - 871, 871, 871, 871, 871, 871, 871, 871, 871, 871, - 871, 871, 872, 872, 873, 873, 874, 874, 874, 875, - 875, 876, 876, 877, 877, 878, 879, 879, 879, 880, - 881, 881, 882, 882, 883, 883, 883, 883, 884, 884, - 885, 885, 885, 885, 885, 886, 886, 886, 886, 886, - 887, 887, 888, 888, 889, 890, 890, 891, 891, 892, - 893, 893, 894, 894, 895, 895, 896, 896, 896, 897, - 897, 898, 898, 898, 898, 898, 898, 898, 898, 898, - 898, 898, 898, 898, 898, 899, 899, 900, 900, 901, - 901, 901, 901, 901, 901, 901, 901, 902, 902, 903, - 903, 904, 904, 905, 905, 906, 906, 907, 907, 908, - 908, 909, 909, 909, 910, 910, 911, 911, 912, 912, - 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, - 912, 912, 912, 913, 913, 914, 915, 915, 916, 916, - 916, 916, 916, 916, 917, 918, 919, 919, 919, 920, - 920, 920, 920, 921, 922, 922, 923, 924, 924, 925, - 925, 926, 927, 927, 563, 563, 563, 563, 928, 928, - 929, 929, 930, 930, 930, 931, 931, 931, 931, 931, - 932, 932, 933, 933, 934, 934, 935, 935, 936, 936, - 937, 937, 937, 937, 938, 938, 939, 939, 940, 940, - 941, 941, 942, 942, 943, 944, 944, 945, 945, 946, - 946, 946, 947, 948, 948, 949, 949, 950, 950, 950, - 951, 951, 952, 952, 953, 953, 954, 954, 955, 956, - 956, 957, 957, 957, 957, 957, 957, 957, 957, 957, - 957, 957, 957, 957, 957, 958, 959, 959, 959, 960, - 960, 960, 961, 961, 961, 962, 962, 963, 963, 964, - 964, 965, 966, 966, 967, 968, 968, 969, 969, 969, - 969, 969, 969, 970, 970, 970, 971, 971, 972, 972, - 972, 972, 973, 973, 974, 975, 975, 976, 976, 977, - 977, 978, 978, 979, 979, 980, 980, 980, 980, 980, - 980, 981, 981, 982, 982, 983, 983, 984, 984, 985, - 985, 985, 985, 985, 985, 985, 985, 985, 985, 986, - 986, 987, 988, 988, 988, 988, 989, 989, 990, 990, - 990, 991, 991, 991, 991, 991, 991, 991, 991, 991, - 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, - 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, - 991, 991, 991, 992, 992, 992, 993, 993, 994, 994, - 995, 995, 996, 996, 996, 996, 997, 998, 998, 999, - 999, 999, 999, 999, 1000, 1000, 1000, 1000, 1001, 1001, - 1002, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1004, 1004, - 1005, 1005, 1005, 1005, 1006, 1006, 1007, 1007, 1008, 1008, - 1008, 1009, 1009, 1009, 1009, 1009, 1010, 1010, 1010, 1010, - 1010, 1011, 1011, 1012, 1012, 1013, 1013, 1014, 1014, 1015, - 1015, 1015, 1016, 1016, 1017, 1017, 1018, 1018, 1019, 1019, - 1019, 1020, 1020, 1020, 1021, 1021, 1022, 1022, 1023, 1023, - 1024, 1025, 1025, 1026, 1026, 1027, 1027, 1027, 1027, 1027, - 1028, 1028, 1029, 1029, 1029, 1030, 1030, 1030, 1030, 1030, - 1030, 1030, 1030, 1030, 1031, 1031, 1032, 1032, 1033, 1033, - 1034, 1034, 1035, 1036, 1036, 1036, 1036, 1036, 1037, 1037, - 1037, 1037, 1038, 1038, 1038, 1039, 1039, 1039, 1040, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, - 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1042, - 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, - 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, - 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, - 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, - 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, - 1042, 1042, 1042, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 859, 859, 860, 860, 860, 860, 860, 860, 860, 860, + 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, + 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, + 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, + 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, + 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, + 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, + 860, 860, 860, 860, 860, 861, 861, 861, 861, 861, + 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, + 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, + 862, 862, 863, 863, 863, 863, 863, 863, 864, 864, + 864, 865, 865, 865, 866, 866, 866, 866, 866, 866, + 866, 866, 866, 866, 867, 868, 869, 870, 870, 870, + 870, 870, 870, 870, 871, 871, 872, 872, 873, 873, + 873, 873, 873, 873, 873, 873, 873, 873, 873, 873, + 873, 873, 874, 874, 875, 875, 876, 876, 876, 877, + 877, 878, 878, 879, 879, 880, 881, 881, 881, 882, + 883, 883, 884, 884, 885, 885, 885, 885, 886, 886, + 887, 887, 887, 887, 887, 888, 888, 888, 888, 888, + 889, 889, 890, 890, 891, 892, 892, 893, 893, 894, + 895, 895, 896, 896, 897, 897, 898, 898, 898, 899, + 899, 900, 900, 900, 900, 900, 900, 900, 900, 900, + 900, 900, 900, 900, 900, 901, 901, 902, 902, 903, + 903, 903, 903, 903, 903, 903, 903, 904, 904, 905, + 905, 906, 906, 907, 907, 908, 908, 909, 909, 910, + 910, 911, 911, 911, 912, 912, 913, 913, 914, 914, + 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, + 914, 914, 914, 915, 915, 916, 917, 917, 918, 918, + 918, 918, 918, 918, 919, 920, 921, 921, 921, 922, + 922, 922, 922, 923, 924, 924, 925, 926, 926, 927, + 927, 928, 929, 929, 563, 563, 563, 563, 930, 930, + 931, 931, 932, 932, 932, 933, 933, 933, 933, 933, + 934, 934, 935, 935, 936, 936, 937, 937, 938, 938, + 939, 939, 939, 939, 940, 940, 941, 941, 942, 942, + 943, 943, 944, 944, 945, 946, 946, 947, 947, 948, + 948, 948, 949, 950, 950, 951, 951, 952, 952, 952, + 953, 953, 954, 954, 955, 955, 956, 956, 957, 958, + 958, 959, 959, 959, 959, 959, 959, 959, 959, 959, + 959, 959, 959, 959, 959, 960, 961, 961, 961, 962, + 962, 962, 963, 963, 963, 964, 964, 965, 965, 966, + 966, 967, 968, 968, 969, 970, 970, 971, 971, 971, + 971, 971, 971, 972, 972, 972, 973, 973, 974, 974, + 974, 974, 975, 975, 976, 977, 977, 978, 978, 979, + 979, 980, 980, 981, 981, 982, 982, 982, 982, 982, + 982, 983, 983, 984, 984, 985, 985, 986, 986, 987, + 987, 987, 987, 987, 987, 987, 987, 987, 987, 988, + 988, 989, 990, 990, 990, 990, 991, 991, 992, 992, + 992, 993, 993, 993, 993, 993, 993, 993, 993, 993, + 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, + 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, + 993, 993, 993, 994, 994, 994, 995, 995, 996, 996, + 997, 997, 998, 998, 998, 998, 999, 1000, 1000, 1001, + 1001, 1001, 1001, 1001, 1002, 1002, 1002, 1002, 1003, 1003, + 1004, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1006, 1006, + 1007, 1007, 1007, 1007, 1008, 1008, 1009, 1009, 1010, 1010, + 1010, 1011, 1011, 1011, 1011, 1011, 1012, 1012, 1012, 1012, + 1012, 1013, 1013, 1014, 1014, 1015, 1015, 1016, 1016, 1017, + 1017, 1017, 1018, 1018, 1019, 1019, 1020, 1020, 1021, 1021, + 1021, 1022, 1022, 1022, 1023, 1023, 1024, 1024, 1025, 1025, + 1026, 1027, 1027, 1028, 1028, 1029, 1029, 1029, 1029, 1029, + 1030, 1030, 1031, 1031, 1031, 1032, 1032, 1032, 1032, 1032, + 1032, 1032, 1032, 1032, 1033, 1033, 1034, 1034, 1035, 1035, + 1036, 1036, 1037, 1038, 1038, 1038, 1038, 1038, 1039, 1039, + 1039, 1039, 1040, 1040, 1040, 1041, 1041, 1041, 1042, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, - 1043, 1043, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, + 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, - 1044, 1044, 1044, 1044, 1045, 1045, 1045, 1045, 1045, 1045, - 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, - 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, - 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, - 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, - 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, + 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, + 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, + 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, + 1044, 1044, 1044, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, - 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1046, 1046, + 1045, 1045, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, - 1046, 1046, 1046, 1047, 1047, 1047, 1047, 1047, 1047, 1047, + 1046, 1046, 1046, 1046, 1047, 1047, 1047, 1047, 1047, 1047, + 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, - 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047 + 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1048, 1048, + 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, + 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, + 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, + 1048, 1048, 1048, 1049, 1049, 1049, 1049, 1049, 1049, 1049, + 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, + 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, + 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, + 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, + 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, + 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, + 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -3463,64 +3473,65 @@ static const yytype_uint8 yyr2[] = 2, 2, 2, 3, 3, 3, 1, 3, 1, 0, 1, 2, 2, 6, 8, 5, 7, 0, 2, 2, 3, 3, 2, 2, 2, 1, 1, 0, 2, 2, - 0, 2, 9, 12, 11, 0, 2, 1, 1, 1, + 0, 2, 10, 13, 12, 0, 2, 1, 1, 1, 1, 1, 1, 3, 0, 1, 2, 1, 1, 2, 2, 3, 1, 1, 2, 2, 1, 2, 3, 5, 3, 2, 5, 1, 1, 1, 0, 5, 7, 5, 2, 3, 1, 1, 2, 2, 0, 3, 4, 4, 0, 3, 2, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 2, 2, - 2, 2, 2, 2, 0, 3, 3, 3, 0, 1, - 2, 1, 2, 2, 2, 2, 2, 3, 2, 2, - 1, 3, 1, 1, 1, 1, 3, 1, 2, 0, - 1, 2, 0, 1, 3, 0, 2, 0, 3, 3, - 1, 5, 3, 1, 3, 1, 2, 1, 4, 5, - 5, 6, 3, 7, 4, 11, 1, 3, 2, 2, - 2, 0, 3, 1, 1, 2, 2, 2, 2, 1, - 0, 1, 2, 6, 4, 6, 4, 6, 8, 1, - 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, - 1, 1, 3, 3, 3, 3, 1, 2, 2, 1, - 3, 1, 1, 1, 3, 1, 1, 0, 1, 1, - 1, 9, 2, 0, 3, 0, 1, 0, 3, 3, - 2, 1, 6, 3, 3, 2, 2, 1, 0, 5, - 2, 2, 0, 7, 1, 1, 1, 2, 5, 8, - 7, 5, 8, 7, 4, 4, 1, 3, 1, 1, - 3, 1, 3, 1, 1, 2, 4, 3, 1, 3, - 2, 4, 4, 8, 11, 9, 7, 0, 3, 3, - 1, 1, 3, 0, 1, 0, 1, 0, 1, 0, - 1, 3, 2, 0, 2, 0, 1, 0, 1, 1, - 1, 3, 3, 1, 1, 3, 3, 3, 3, 3, - 3, 4, 3, 2, 1, 1, 1, 3, 1, 3, - 1, 1, 1, 3, 3, 3, 1, 2, 4, 4, - 2, 3, 5, 5, 1, 1, 3, 0, 11, 11, - 10, 12, 1, 2, 5, 4, 4, 4, 4, 7, - 5, 4, 7, 6, 9, 9, 4, 1, 1, 1, - 1, 1, 1, 1, 5, 1, 1, 3, 1, 2, - 2, 2, 3, 1, 3, 8, 5, 0, 1, 2, - 1, 3, 1, 2, 0, 2, 0, 3, 3, 4, - 4, 4, 4, 3, 2, 1, 1, 0, 1, 1, - 0, 2, 1, 5, 1, 0, 2, 2, 0, 1, - 0, 3, 5, 1, 3, 4, 3, 1, 1, 0, - 2, 2, 0, 2, 2, 1, 1, 1, 0, 2, - 4, 5, 4, 2, 3, 1, 1, 1, 2, 2, - 1, 2, 3, 0, 1, 0, 5, 1, 4, 6, - 2, 1, 0, 4, 0, 1, 1, 3, 4, 0, - 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, - 1, 1, 1, 1, 1, 3, 3, 0, 1, 3, - 1, 2, 1, 1, 1, 1, 1, 2, 4, 4, - 5, 1, 1, 2, 0, 2, 0, 1, 3, 1, - 0, 1, 2, 3, 2, 4, 2, 3, 2, 0, - 1, 2, 0, 4, 5, 1, 2, 2, 0, 1, - 3, 1, 2, 2, 4, 4, 3, 3, 3, 3, - 3, 3, 3, 1, 4, 4, 9, 9, 3, 0, - 2, 2, 0, 5, 3, 1, 1, 3, 5, 3, - 1, 2, 1, 3, 5, 1, 2, 3, 4, 5, - 4, 5, 4, 6, 5, 4, 5, 5, 5, 2, - 4, 1, 1, 0, 1, 4, 5, 4, 0, 2, - 2, 2, 1, 1, 1, 1, 0, 4, 2, 1, - 2, 2, 4, 2, 6, 2, 1, 3, 4, 0, - 2, 0, 2, 0, 1, 3, 3, 2, 0, 2, - 4, 1, 1, 1, 0, 2, 3, 5, 6, 2, + 2, 2, 0, 5, 5, 2, 2, 2, 0, 3, + 3, 3, 0, 1, 2, 1, 2, 2, 2, 2, + 2, 3, 2, 2, 1, 3, 1, 1, 1, 1, + 3, 1, 2, 0, 1, 2, 0, 1, 3, 0, + 2, 0, 3, 3, 1, 5, 3, 3, 1, 1, + 3, 1, 2, 1, 4, 5, 5, 6, 3, 7, + 4, 11, 1, 3, 2, 2, 2, 0, 3, 1, + 1, 2, 2, 2, 2, 1, 0, 1, 2, 6, + 4, 6, 4, 6, 8, 1, 1, 1, 1, 2, + 1, 2, 1, 2, 1, 1, 1, 1, 3, 3, + 3, 3, 1, 2, 2, 1, 3, 1, 1, 1, + 3, 1, 1, 0, 1, 1, 1, 9, 2, 0, + 3, 0, 1, 0, 3, 3, 2, 1, 6, 3, + 3, 2, 2, 1, 0, 5, 2, 2, 0, 7, + 1, 1, 1, 2, 5, 8, 7, 5, 8, 7, + 4, 4, 1, 3, 1, 1, 3, 1, 3, 1, + 1, 2, 4, 3, 1, 3, 2, 4, 4, 8, + 11, 9, 7, 0, 3, 3, 1, 1, 3, 0, + 1, 0, 1, 0, 1, 0, 1, 3, 2, 0, + 2, 0, 1, 0, 1, 1, 1, 3, 3, 1, + 1, 3, 3, 3, 3, 3, 3, 4, 3, 2, + 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, + 3, 3, 1, 2, 4, 4, 2, 3, 5, 5, + 1, 1, 3, 0, 11, 11, 10, 12, 1, 2, + 5, 4, 4, 4, 4, 7, 5, 4, 7, 6, + 9, 9, 4, 1, 1, 1, 1, 1, 1, 1, + 5, 1, 1, 3, 1, 2, 2, 2, 3, 1, + 3, 8, 5, 0, 1, 2, 1, 3, 1, 2, + 0, 2, 0, 3, 3, 4, 4, 4, 4, 3, + 2, 1, 1, 0, 1, 1, 0, 2, 1, 5, + 1, 0, 2, 2, 0, 1, 0, 3, 5, 1, + 3, 4, 3, 1, 1, 0, 2, 2, 0, 2, + 2, 1, 1, 1, 0, 2, 4, 5, 4, 2, + 3, 1, 1, 1, 2, 2, 1, 2, 3, 0, + 1, 0, 5, 1, 4, 6, 2, 1, 0, 4, + 0, 1, 1, 3, 4, 0, 1, 1, 2, 2, + 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, + 1, 3, 3, 0, 1, 3, 1, 2, 1, 1, + 1, 1, 1, 2, 4, 4, 5, 1, 1, 2, + 0, 2, 0, 1, 3, 1, 0, 1, 2, 3, + 2, 4, 2, 3, 2, 0, 1, 2, 0, 4, + 5, 1, 2, 2, 0, 1, 3, 1, 2, 2, + 4, 4, 3, 3, 3, 3, 3, 3, 3, 1, + 4, 4, 9, 9, 3, 0, 2, 2, 0, 5, + 3, 1, 1, 3, 5, 3, 1, 2, 1, 3, + 5, 1, 2, 3, 4, 5, 4, 5, 4, 6, + 5, 4, 5, 5, 5, 2, 4, 1, 1, 0, + 1, 4, 5, 4, 0, 2, 2, 2, 1, 1, + 1, 1, 0, 4, 2, 1, 2, 2, 4, 2, + 6, 2, 1, 3, 4, 0, 2, 0, 2, 0, + 1, 3, 3, 2, 0, 2, 4, 1, 1, 1, + 0, 2, 3, 5, 5, 6, 6, 2, 2, 3, 3, 2, 5, 5, 5, 3, 3, 3, 4, 0, 1, 1, 1, 1, 1, 2, 4, 1, 1, 1, 1, 2, 3, 0, 1, 1, 1, 1, 1, 2, @@ -3595,7 +3606,7 @@ static const yytype_uint8 yyr2[] = 1, 1, 1, 2, 3, 2, 2, 2, 4, 2, 3, 4, 3, 1, 1, 1, 1, 1, 1, 0, 1, 3, 2, 9, 12, 11, 12, 14, 3, 4, - 4, 0, 7, 10, 9, 2, 3, 0, 4, 1, + 4, 0, 7, 10, 9, 2, 3, 0, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -3667,1990 +3678,1984 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint16 yydefact[] = { - 169, 287, 0, 1491, 1490, 1565, 287, 0, 1424, 0, - 287, 547, 430, 0, 1595, 1594, 0, 224, 287, 0, - 169, 0, 1525, 0, 0, 0, 609, 612, 610, 0, - 0, 0, 287, 655, 0, 1596, 287, 0, 0, 647, - 611, 0, 1542, 0, 0, 0, 0, 0, 2, 4, + 169, 287, 0, 1501, 1500, 1575, 287, 0, 1434, 0, + 287, 553, 436, 0, 1605, 1604, 0, 224, 287, 0, + 169, 0, 1535, 0, 0, 0, 615, 618, 616, 0, + 0, 0, 287, 661, 0, 1606, 287, 0, 0, 653, + 617, 0, 1552, 0, 0, 0, 0, 0, 2, 4, 8, 22, 37, 32, 0, 21, 35, 19, 18, 40, 27, 7, 5, 25, 39, 42, 20, 26, 34, 16, - 41, 14, 38, 585, 571, 660, 584, 0, 0, 168, - 765, 592, 36, 17, 31, 6, 12, 13, 29, 30, - 28, 1447, 45, 33, 0, 43, 23, 9, 10, 24, - 44, 46, 1597, 1593, 11, 47, 15, 286, 285, 279, - 0, 0, 0, 0, 0, 0, 1564, 0, 0, 0, - 290, 125, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626, - 1627, 1628, 1629, 2003, 1630, 1631, 2004, 1632, 1633, 2005, - 1634, 1635, 1636, 1949, 1950, 2006, 1951, 1952, 1637, 1638, - 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1953, 1954, 1646, - 1647, 1648, 1649, 1650, 1955, 2007, 1956, 1651, 1652, 1653, - 1654, 1655, 2008, 1656, 1657, 1658, 1659, 1660, 1661, 1662, - 1663, 1664, 2009, 1665, 1666, 1667, 1668, 1669, 1670, 1671, - 1672, 1673, 1674, 1957, 1675, 1676, 1958, 1677, 1678, 1679, - 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, + 41, 14, 38, 591, 577, 666, 590, 0, 0, 168, + 771, 598, 36, 17, 31, 6, 12, 13, 29, 30, + 28, 1457, 45, 33, 0, 43, 23, 9, 10, 24, + 44, 46, 1607, 1603, 11, 47, 15, 286, 285, 279, + 0, 0, 0, 0, 0, 0, 1574, 0, 0, 0, + 290, 125, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, + 1637, 1638, 1639, 2013, 1640, 1641, 2014, 1642, 1643, 2015, + 1644, 1645, 1646, 1959, 1960, 2016, 1961, 1962, 1647, 1648, + 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1963, 1964, 1656, + 1657, 1658, 1659, 1660, 1965, 2017, 1966, 1661, 1662, 1663, + 1664, 1665, 2018, 1666, 1667, 1668, 1669, 1670, 1671, 1672, + 1673, 1674, 2019, 1675, 1676, 1677, 1678, 1679, 1680, 1681, + 1682, 1683, 1684, 1967, 1685, 1686, 1968, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, - 1700, 1701, 1702, 1703, 1704, 1959, 1705, 1706, 1707, 1708, - 1709, 1710, 1960, 1711, 1712, 1713, 1961, 1714, 1715, 1716, - 2010, 2011, 1717, 1718, 1962, 2013, 1719, 1720, 1721, 1963, - 1964, 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, 1730, - 2014, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739, - 1740, 1741, 1742, 2015, 1965, 1743, 1744, 1745, 1746, 1747, - 1966, 1967, 1968, 1748, 2016, 2017, 1749, 2018, 1750, 1751, - 1752, 1753, 1754, 1755, 1756, 2019, 1757, 2020, 1758, 1759, - 1760, 1761, 1762, 1763, 1764, 1765, 1969, 1766, 1767, 1768, - 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, - 1779, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1970, - 2022, 1971, 1788, 1789, 1790, 1972, 1791, 1792, 2023, 1793, - 1973, 1794, 1974, 1795, 1796, 1797, 1798, 1799, 1800, 1801, - 1802, 1803, 1804, 1975, 2024, 1805, 2025, 1976, 1806, 1807, - 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, - 1818, 1819, 1977, 2026, 1820, 1821, 1978, 1822, 1823, 1824, - 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, 1834, - 1835, 1979, 1836, 1837, 1838, 1839, 1840, 1841, 1842, 1843, - 1844, 1845, 1846, 1847, 1848, 1849, 1850, 1851, 1852, 1853, - 1854, 2027, 1855, 1856, 1857, 1980, 1858, 1859, 1860, 1861, - 1862, 1863, 1864, 1865, 1866, 1867, 1868, 1869, 1870, 1871, - 1872, 1873, 1874, 1875, 1876, 1981, 1877, 1878, 2028, 1879, - 1880, 1982, 1881, 1882, 1883, 1884, 1885, 1886, 1887, 1888, - 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1983, 1896, 1984, - 1897, 1898, 1899, 2030, 1900, 1901, 1902, 1903, 1904, 1905, - 1906, 1985, 1986, 1907, 1908, 1987, 1909, 1988, 1910, 1911, - 1989, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, - 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1990, 1991, - 1929, 1930, 2031, 1931, 1932, 1933, 1934, 1935, 1936, 1937, - 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1992, 1993, 1994, - 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 1945, 1946, - 1947, 1948, 0, 1602, 0, 1349, 126, 127, 1371, 125, - 1962, 1969, 1983, 1423, 1422, 126, 0, 282, 546, 0, - 0, 0, 0, 0, 0, 226, 0, 424, 423, 1413, - 429, 0, 0, 0, 129, 121, 1822, 128, 1348, 119, - 135, 2183, 2184, 2185, 2186, 2064, 2187, 2188, 2189, 2190, - 2065, 2191, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2192, - 2073, 2193, 2194, 2075, 2074, 2195, 2076, 2196, 2077, 2197, - 2078, 2079, 2198, 2199, 2080, 1671, 2081, 2082, 2200, 2201, - 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2083, 2084, 2209, - 2210, 2085, 2211, 2212, 2086, 2213, 2087, 2088, 2089, 2214, - 2090, 2091, 2215, 2092, 2216, 2217, 2093, 2094, 2097, 2095, - 2218, 2096, 2219, 2098, 2099, 2100, 2220, 2221, 2222, 2101, - 2102, 2223, 2103, 2104, 2105, 2106, 2107, 2224, 2108, 2225, - 2109, 2110, 2226, 2227, 2228, 2229, 2230, 2112, 2111, 2113, - 2114, 2231, 2232, 2233, 2234, 2115, 2116, 2117, 2235, 2236, - 2118, 2237, 2238, 2119, 2120, 2239, 2121, 2122, 2240, 2123, - 2124, 2241, 2125, 2126, 2242, 2243, 2244, 2127, 2245, 2128, - 2129, 2246, 2247, 2130, 2131, 2248, 2132, 2249, 2250, 2133, - 2251, 2252, 2134, 2135, 2253, 2136, 2254, 2255, 2256, 2257, - 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, - 2147, 1561, 137, 136, 138, 0, 448, 449, 0, 459, - 0, 441, 446, 442, 0, 468, 461, 469, 450, 440, - 462, 451, 439, 225, 0, 470, 456, 444, 0, 0, - 0, 0, 283, 242, 0, 430, 0, 169, 0, 1453, - 1463, 1473, 1468, 1462, 1471, 1460, 1477, 1466, 1452, 1475, - 1461, 1465, 1470, 1458, 1476, 1456, 1474, 1472, 1459, 1467, - 1451, 1455, 1442, 1447, 1480, 1469, 1478, 1464, 1479, 1481, - 1454, 1482, 1457, 0, 1424, 0, 1955, 2007, 1960, 0, - 1973, 0, 1976, 1977, 1858, 1984, 1987, 1988, 1989, 1990, - 0, 839, 128, 123, 823, 0, 587, 0, 769, 783, - 823, 828, 1116, 851, 1117, 0, 130, 1527, 1526, 1520, - 211, 1386, 1581, 1719, 1760, 1875, 1985, 1907, 1929, 1600, - 1582, 1575, 1580, 284, 654, 652, 0, 1305, 1719, 1760, - 1862, 1875, 1985, 1929, 1499, 1504, 0, 290, 1587, 128, - 123, 1586, 0, 593, 646, 0, 291, 1541, 0, 1546, - 0, 1838, 620, 623, 1380, 621, 585, 0, 0, 1, - 169, 0, 175, 0, 0, 650, 650, 0, 650, 0, - 577, 0, 0, 585, 580, 584, 766, 1446, 1556, 0, - 1599, 1899, 1985, 1907, 1589, 1585, 1729, 0, 1729, 0, - 0, 1729, 0, 1729, 0, 1729, 0, 0, 1565, 1567, - 0, 280, 1289, 0, 1350, 131, 0, 0, 1435, 1431, - 1436, 1432, 1437, 1430, 1429, 1438, 1434, 0, 0, 0, - 395, 428, 427, 426, 425, 430, 1729, 1397, 222, 513, - 514, 0, 0, 0, 0, 0, 0, 1408, 122, 120, - 1729, 1562, 457, 458, 0, 447, 443, 445, 0, 0, - 1729, 1375, 467, 463, 1729, 467, 1342, 1729, 0, 0, - 234, 0, 423, 1444, 1483, 2134, 1497, 0, 1498, 1488, - 1450, 1484, 1485, 169, 0, 545, 1421, 0, 0, 0, - 1237, 823, 828, 0, 0, 841, 0, 1257, 0, 1263, - 0, 0, 0, 823, 592, 0, 783, 840, 124, 773, - 0, 821, 822, 702, 702, 655, 0, 636, 0, 702, - 709, 702, 833, 0, 0, 836, 834, 0, 836, 0, - 0, 0, 836, 832, 792, 0, 709, 0, 821, 824, - 702, 0, 843, 1441, 0, 0, 0, 0, 1578, 1576, - 1577, 1583, 0, 1579, 0, 0, 1352, 1354, 1355, 1205, - 1365, 1092, 0, 1950, 1951, 1952, 1280, 1953, 1954, 1956, - 1957, 1958, 1049, 1691, 1959, 1363, 1961, 1963, 1964, 1966, - 1967, 1968, 0, 1969, 1970, 1971, 0, 1364, 1974, 1800, - 1979, 1980, 1982, 1985, 1986, 1362, 0, 1991, 0, 0, - 0, 1323, 1228, 0, 1091, 0, 0, 0, 1282, 1290, - 1084, 0, 0, 887, 888, 909, 910, 889, 915, 916, - 918, 890, 0, 1312, 982, 1080, 1300, 1094, 1089, 1099, - 1095, 1096, 1135, 1097, 1115, 1100, 1172, 1090, 0, 1098, - 1082, 1308, 636, 1306, 0, 1083, 1351, 636, 1304, 1502, - 1500, 1507, 1501, 0, 1503, 0, 0, 0, 281, 124, - 1549, 1548, 1540, 1538, 1539, 1537, 1536, 1543, 0, 1545, - 1447, 1282, 1223, 1225, 0, 622, 0, 0, 627, 574, - 573, 575, 3, 0, 0, 0, 0, 1709, 0, 648, - 649, 0, 0, 0, 0, 0, 0, 0, 0, 750, - 675, 676, 678, 747, 751, 759, 0, 0, 0, 0, - 0, 581, 0, 1380, 1528, 1598, 1592, 0, 1590, 0, + 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, + 1710, 1711, 1712, 1713, 1714, 1969, 1715, 1716, 1717, 1718, + 1719, 1720, 1970, 1721, 1722, 1723, 1971, 1724, 1725, 1726, + 2020, 2021, 1727, 1728, 1972, 2023, 1729, 1730, 1731, 1973, + 1974, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739, 1740, + 2024, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, + 1750, 1751, 1752, 2025, 1975, 1753, 1754, 1755, 1756, 1757, + 1976, 1977, 1978, 1758, 2026, 2027, 1759, 2028, 1760, 1761, + 1762, 1763, 1764, 1765, 1766, 2029, 1767, 2030, 1768, 1769, + 1770, 1771, 1772, 1773, 1774, 1775, 1979, 1776, 1777, 1778, + 1779, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, + 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, 1797, 1980, + 2032, 1981, 1798, 1799, 1800, 1982, 1801, 1802, 2033, 1803, + 1983, 1804, 1984, 1805, 1806, 1807, 1808, 1809, 1810, 1811, + 1812, 1813, 1814, 1985, 2034, 1815, 2035, 1986, 1816, 1817, + 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, + 1828, 1829, 1987, 2036, 1830, 1831, 1988, 1832, 1833, 1834, + 1835, 1836, 1837, 1838, 1839, 1840, 1841, 1842, 1843, 1844, + 1845, 1989, 1846, 1847, 1848, 1849, 1850, 1851, 1852, 1853, + 1854, 1855, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, + 1864, 2037, 1865, 1866, 1867, 1990, 1868, 1869, 1870, 1871, + 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, + 1882, 1883, 1884, 1885, 1886, 1991, 1887, 1888, 2038, 1889, + 1890, 1992, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, + 1899, 1900, 1901, 1902, 1903, 1904, 1905, 1993, 1906, 1994, + 1907, 1908, 1909, 2040, 1910, 1911, 1912, 1913, 1914, 1915, + 1916, 1995, 1996, 1917, 1918, 1997, 1919, 1998, 1920, 1921, + 1999, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, + 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 2000, 2001, + 1939, 1940, 2041, 1941, 1942, 1943, 1944, 1945, 1946, 1947, + 1948, 1949, 1950, 1951, 1952, 1953, 1954, 2002, 2003, 2004, + 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 1955, 1956, + 1957, 1958, 0, 1612, 0, 1359, 126, 127, 1381, 125, + 1972, 1979, 1993, 1433, 1432, 126, 0, 282, 552, 0, + 0, 0, 0, 0, 0, 226, 0, 430, 429, 1423, + 435, 0, 0, 0, 129, 121, 1832, 128, 1358, 119, + 135, 2193, 2194, 2195, 2196, 2074, 2197, 2198, 2199, 2200, + 2075, 2201, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2202, + 2083, 2203, 2204, 2085, 2084, 2205, 2086, 2206, 2087, 2207, + 2088, 2089, 2208, 2209, 2090, 1681, 2091, 2092, 2210, 2211, + 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2093, 2094, 2219, + 2220, 2095, 2221, 2222, 2096, 2223, 2097, 2098, 2099, 2224, + 2100, 2101, 2225, 2102, 2226, 2227, 2103, 2104, 2107, 2105, + 2228, 2106, 2229, 2108, 2109, 2110, 2230, 2231, 2232, 2111, + 2112, 2233, 2113, 2114, 2115, 2116, 2117, 2234, 2118, 2235, + 2119, 2120, 2236, 2237, 2238, 2239, 2240, 2122, 2121, 2123, + 2124, 2241, 2242, 2243, 2244, 2125, 2126, 2127, 2245, 2246, + 2128, 2247, 2248, 2129, 2130, 2249, 2131, 2132, 2250, 2133, + 2134, 2251, 2135, 2136, 2252, 2253, 2254, 2137, 2255, 2138, + 2139, 2256, 2257, 2140, 2141, 2258, 2142, 2259, 2260, 2143, + 2261, 2262, 2144, 2145, 2263, 2146, 2264, 2265, 2266, 2267, + 2147, 2148, 2149, 2150, 2151, 2152, 2153, 2154, 2155, 2156, + 2157, 1571, 137, 136, 138, 0, 454, 455, 0, 465, + 0, 447, 452, 448, 0, 474, 467, 475, 456, 446, + 468, 457, 445, 225, 0, 476, 462, 450, 0, 0, + 0, 0, 283, 242, 0, 436, 0, 169, 0, 1463, + 1473, 1483, 1478, 1472, 1481, 1470, 1487, 1476, 1462, 1485, + 1471, 1475, 1480, 1468, 1486, 1466, 1484, 1482, 1469, 1477, + 1461, 1465, 1452, 1457, 1490, 1479, 1488, 1474, 1489, 1491, + 1464, 1492, 1467, 0, 1434, 0, 1965, 2017, 1970, 0, + 1983, 0, 1986, 1987, 1868, 1994, 1997, 1998, 1999, 2000, + 0, 845, 128, 123, 829, 0, 593, 0, 775, 789, + 829, 834, 1126, 857, 1127, 0, 130, 1537, 1536, 1530, + 211, 1396, 1591, 1729, 1770, 1885, 1995, 1917, 1939, 1610, + 1592, 1585, 1590, 284, 660, 658, 0, 1315, 1729, 1770, + 1872, 1885, 1995, 1939, 1509, 1514, 0, 290, 1597, 128, + 123, 1596, 0, 599, 652, 0, 291, 1551, 0, 1556, + 0, 1848, 626, 629, 1390, 627, 591, 0, 0, 1, + 169, 0, 175, 0, 0, 656, 656, 0, 656, 0, + 583, 0, 0, 591, 586, 590, 772, 1456, 1566, 0, + 1609, 1909, 1995, 1917, 1599, 1595, 1739, 0, 1739, 0, + 0, 1739, 0, 1739, 0, 1739, 0, 0, 1575, 1577, + 0, 280, 1299, 0, 1360, 131, 0, 0, 1445, 1441, + 1446, 1442, 1447, 1440, 1439, 1448, 1444, 0, 0, 0, + 399, 434, 433, 432, 431, 436, 1739, 1407, 222, 519, + 520, 0, 0, 0, 0, 0, 0, 1418, 122, 120, + 1739, 1572, 463, 464, 0, 453, 449, 451, 0, 0, + 1739, 1385, 473, 469, 1739, 473, 1352, 1739, 0, 0, + 234, 0, 429, 1454, 1493, 2144, 1507, 0, 1508, 1498, + 1460, 1494, 1495, 169, 0, 551, 1431, 0, 0, 0, + 1247, 829, 834, 0, 0, 847, 0, 1267, 0, 1273, + 0, 0, 0, 829, 598, 0, 789, 846, 124, 779, + 0, 827, 828, 708, 708, 661, 0, 642, 0, 708, + 715, 708, 839, 0, 0, 842, 840, 0, 842, 0, + 0, 0, 842, 838, 798, 0, 715, 0, 827, 830, + 708, 0, 849, 1451, 0, 0, 0, 0, 1588, 1586, + 1587, 1593, 0, 1589, 0, 0, 1362, 1364, 1365, 1215, + 1375, 1102, 0, 1960, 1961, 1962, 1290, 1963, 1964, 1966, + 1967, 1968, 1059, 1701, 1969, 1373, 1971, 1973, 1974, 1976, + 1977, 1978, 0, 1979, 1980, 1981, 0, 1374, 1984, 1810, + 1989, 1990, 1992, 1995, 1996, 1372, 0, 2001, 0, 0, + 0, 1333, 1238, 0, 1101, 0, 0, 0, 1292, 1300, + 1094, 0, 0, 897, 898, 919, 920, 899, 925, 926, + 928, 900, 0, 1322, 992, 1090, 1310, 1104, 1099, 1109, + 1105, 1106, 1145, 1107, 1125, 1110, 1182, 1100, 0, 1108, + 1092, 1318, 642, 1316, 0, 1093, 1361, 642, 1314, 1512, + 1510, 1517, 1511, 0, 1513, 0, 0, 0, 281, 124, + 1559, 1558, 1550, 1548, 1549, 1547, 1546, 1553, 0, 1555, + 1457, 1292, 1233, 1235, 0, 628, 0, 0, 633, 580, + 579, 581, 3, 0, 0, 0, 0, 1719, 0, 654, + 655, 0, 0, 0, 0, 0, 0, 0, 0, 756, + 681, 682, 684, 753, 757, 765, 0, 0, 0, 0, + 0, 587, 0, 1390, 1538, 1608, 1602, 0, 1600, 0, 0, 0, 0, 0, 153, 153, 0, 0, 0, 0, 0, 113, 51, 106, 0, 0, 0, 0, 256, 269, 0, 0, 0, 0, 0, 266, 0, 0, 249, 53, 243, 245, 0, 153, 0, 49, 0, 0, 0, 55, - 1565, 0, 0, 1574, 288, 289, 1288, 0, 133, 134, - 132, 125, 0, 2148, 2003, 2004, 2005, 2006, 2153, 2007, - 1956, 2008, 2009, 0, 2010, 2011, 1962, 2013, 2014, 2015, - 2016, 2017, 2018, 2019, 2020, 1969, 2022, 2023, 2024, 2025, - 2026, 2027, 2176, 2028, 1983, 2030, 1989, 2181, 0, 2031, - 1107, 658, 1231, 660, 1229, 1381, 0, 126, 1368, 0, - 1433, 0, 0, 0, 0, 543, 0, 0, 0, 0, - 1393, 1729, 223, 227, 0, 1729, 218, 1729, 395, 0, - 1729, 0, 1729, 395, 1729, 0, 1407, 1410, 0, 460, - 455, 453, 452, 454, 1729, 277, 0, 0, 1376, 465, - 466, 0, 434, 0, 0, 436, 0, 0, 239, 0, - 237, 0, 430, 169, 0, 250, 1493, 1494, 1492, 0, - 0, 1487, 1449, 253, 270, 1496, 1486, 1495, 1448, 1443, - 0, 0, 1439, 540, 0, 0, 0, 1238, 958, 957, - 939, 940, 955, 956, 941, 942, 949, 950, 960, 959, - 947, 948, 943, 944, 937, 938, 953, 954, 945, 946, - 951, 952, 935, 936, 1252, 1239, 1240, 1241, 1242, 1243, - 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 0, 0, - 782, 779, 0, 0, 0, 0, 0, 0, 1282, 0, - 1055, 1090, 0, 0, 0, 1223, 1262, 0, 0, 0, - 0, 0, 0, 1223, 1268, 0, 0, 807, 819, 0, - 695, 701, 780, 778, 0, 1305, 770, 0, 853, 783, - 781, 0, 702, 777, 0, 833, 0, 832, 0, 0, - 835, 829, 0, 830, 0, 0, 0, 0, 831, 0, - 0, 0, 0, 0, 702, 0, 819, 0, 776, 850, - 1510, 1518, 212, 0, 1372, 2032, 2033, 2034, 2035, 897, - 2036, 926, 904, 2037, 926, 926, 2038, 2039, 2040, 2041, - 893, 893, 906, 2042, 2043, 2044, 2045, 2046, 894, 895, - 931, 2047, 2048, 2049, 2050, 2051, 0, 0, 2052, 926, - 2053, 893, 2054, 2055, 2056, 898, 2057, 861, 2058, 0, - 2059, 896, 862, 2060, 934, 934, 2061, 0, 2062, 921, - 2063, 0, 1234, 879, 879, 880, 881, 882, 907, 908, - 883, 913, 914, 884, 981, 0, 893, 1373, 1374, 169, - 1584, 1601, 0, 1228, 1101, 925, 912, 1279, 0, 920, - 919, 0, 1228, 902, 901, 900, 1086, 0, 899, 0, - 1185, 926, 926, 924, 1007, 903, 0, 0, 0, 0, - 0, 930, 0, 928, 0, 1008, 986, 987, 0, 0, - 1322, 1331, 1223, 1227, 0, 1084, 1223, 0, 1093, 1103, - 0, 1175, 1177, 0, 0, 0, 1283, 1353, 1085, 0, - 1358, 0, 0, 981, 981, 1311, 1205, 0, 1195, 1198, - 0, 0, 1202, 1203, 1204, 0, 0, 0, 1303, 0, - 1213, 1215, 0, 0, 1023, 1211, 0, 1026, 0, 0, - 0, 0, 1199, 1200, 1201, 1191, 1192, 1193, 1194, 1196, - 1197, 1209, 1190, 1004, 0, 1081, 0, 1138, 0, 1003, - 1309, 768, 0, 1356, 768, 1512, 1516, 1517, 1511, 1515, - 0, 1506, 1505, 1508, 1509, 0, 1550, 1534, 0, 1531, - 1226, 763, 624, 1344, 0, 0, 0, 1555, 174, 173, - 0, 0, 233, 0, 597, 596, 669, 661, 663, 669, - 0, 595, 0, 723, 724, 0, 0, 0, 0, 756, - 754, 1352, 1365, 711, 679, 710, 0, 0, 683, 0, - 715, 982, 749, 579, 673, 674, 677, 578, 0, 752, - 0, 762, 0, 616, 618, 601, 615, 613, 598, 606, - 750, 678, 0, 1557, 0, 0, 1521, 1588, 1591, 0, - 0, 0, 0, 0, 0, 0, 1729, 0, 0, 864, + 1575, 0, 0, 1584, 288, 289, 1298, 0, 133, 134, + 132, 125, 0, 2158, 2013, 2014, 2015, 2016, 2163, 2017, + 1966, 2018, 2019, 0, 2020, 2021, 1972, 2023, 2024, 2025, + 2026, 2027, 2028, 2029, 2030, 1979, 2032, 2033, 2034, 2035, + 2036, 2037, 2186, 2038, 1993, 2040, 1999, 2191, 0, 2041, + 1117, 664, 1241, 666, 1239, 1391, 0, 126, 1378, 0, + 1443, 0, 0, 0, 0, 549, 0, 0, 0, 0, + 1403, 1739, 223, 227, 0, 1739, 218, 1739, 399, 0, + 1739, 0, 1739, 399, 1739, 0, 1417, 1420, 0, 466, + 461, 459, 458, 460, 1739, 277, 0, 0, 1386, 471, + 472, 0, 440, 0, 0, 442, 0, 0, 239, 0, + 237, 0, 436, 169, 0, 250, 1503, 1504, 1502, 0, + 0, 1497, 1459, 253, 270, 1506, 1496, 1505, 1458, 1453, + 0, 0, 1449, 546, 0, 0, 0, 1248, 968, 967, + 949, 950, 965, 966, 951, 952, 959, 960, 970, 969, + 957, 958, 953, 954, 947, 948, 963, 964, 955, 956, + 961, 962, 945, 946, 1262, 1249, 1250, 1251, 1252, 1253, + 1254, 1255, 1256, 1257, 1258, 1259, 1260, 1261, 0, 0, + 788, 785, 0, 0, 0, 0, 0, 0, 1292, 0, + 1065, 1100, 0, 0, 0, 1233, 1272, 0, 0, 0, + 0, 0, 0, 1233, 1278, 0, 0, 813, 825, 0, + 701, 707, 786, 784, 0, 1315, 776, 0, 859, 789, + 787, 0, 708, 783, 0, 839, 0, 838, 0, 0, + 841, 835, 0, 836, 0, 0, 0, 0, 837, 0, + 0, 0, 0, 0, 708, 0, 825, 0, 782, 856, + 1520, 1528, 212, 0, 1382, 2042, 2043, 2044, 2045, 907, + 2046, 936, 914, 2047, 936, 936, 2048, 2049, 2050, 2051, + 903, 903, 916, 2052, 2053, 2054, 2055, 2056, 904, 905, + 941, 2057, 2058, 2059, 2060, 2061, 0, 0, 2062, 936, + 2063, 903, 2064, 2065, 2066, 908, 2067, 867, 2068, 0, + 2069, 906, 868, 2070, 944, 944, 2071, 0, 2072, 931, + 2073, 0, 1244, 889, 889, 890, 891, 892, 917, 918, + 893, 923, 924, 894, 991, 0, 903, 1383, 1384, 169, + 1594, 1611, 0, 1238, 1111, 935, 922, 1289, 0, 930, + 929, 0, 1238, 912, 911, 910, 1096, 0, 909, 0, + 1195, 936, 936, 934, 1017, 913, 0, 0, 0, 0, + 0, 940, 0, 938, 0, 1018, 996, 997, 0, 0, + 1332, 1341, 1233, 1237, 0, 1094, 1233, 0, 1103, 1113, + 0, 1185, 1187, 0, 0, 0, 1293, 1363, 1095, 0, + 1368, 0, 0, 991, 991, 1321, 1215, 0, 1205, 1208, + 0, 0, 1212, 1213, 1214, 0, 0, 0, 1313, 0, + 1223, 1225, 0, 0, 1033, 1221, 0, 1036, 0, 0, + 0, 0, 1209, 1210, 1211, 1201, 1202, 1203, 1204, 1206, + 1207, 1219, 1200, 1014, 0, 1091, 0, 1148, 0, 1013, + 1319, 774, 0, 1366, 774, 1522, 1526, 1527, 1521, 1525, + 0, 1516, 1515, 1518, 1519, 0, 1560, 1544, 0, 1541, + 1236, 769, 630, 1354, 0, 0, 0, 1565, 174, 173, + 0, 0, 233, 0, 603, 602, 675, 667, 669, 675, + 0, 601, 0, 729, 730, 0, 0, 0, 0, 762, + 760, 1362, 1375, 717, 685, 716, 0, 0, 689, 0, + 721, 992, 755, 585, 679, 680, 683, 584, 0, 758, + 0, 768, 0, 622, 624, 607, 621, 619, 604, 612, + 756, 684, 0, 1567, 0, 0, 1531, 1598, 1601, 0, + 0, 0, 0, 0, 0, 0, 1739, 0, 0, 870, 74, 70, 97, 345, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 102, 0, 0, 103, 104, - 0, 0, 0, 0, 1372, 254, 255, 268, 0, 259, + 0, 0, 0, 0, 1382, 254, 255, 268, 0, 259, 260, 257, 261, 262, 0, 0, 247, 248, 0, 0, 0, 0, 246, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1567, 1566, 0, 1558, 1284, 1289, 660, 660, - 660, 0, 0, 0, 0, 658, 659, 0, 0, 0, - 0, 0, 539, 393, 403, 0, 0, 0, 1397, 222, - 0, 0, 0, 0, 0, 0, 0, 430, 1400, 1398, - 1396, 1399, 1401, 0, 0, 0, 0, 0, 214, 217, - 0, 392, 364, 0, 0, 0, 0, 1412, 0, 0, - 508, 506, 509, 498, 511, 501, 0, 1729, 382, 1409, - 0, 1563, 0, 0, 275, 467, 1377, 0, 464, 467, - 1343, 0, 467, 241, 0, 0, 1445, 1489, 251, 271, - 252, 272, 545, 1569, 1571, 0, 548, 553, 537, 0, - 537, 0, 550, 554, 537, 549, 0, 537, 544, 0, - 1131, 0, 1121, 0, 0, 842, 0, 0, 1122, 1057, - 1058, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1075, - 1074, 1123, 846, 0, 849, 0, 0, 1260, 1261, 0, - 1124, 0, 0, 1267, 0, 0, 0, 1129, 0, 784, - 0, 0, 685, 686, 694, 690, 697, 0, 700, 687, - 636, 586, 1719, 1760, 0, 647, 647, 647, 645, 635, - 0, 727, 785, 0, 775, 0, 0, 0, 808, 0, - 0, 810, 812, 0, 0, 815, 0, 791, 790, 0, - 0, 774, 0, 0, 854, 0, 1348, 0, 0, 213, - 0, 0, 0, 879, 0, 0, 0, 871, 869, 865, - 0, 961, 962, 963, 964, 965, 966, 967, 968, 969, - 970, 971, 972, 973, 885, 1385, 0, 891, 1388, 0, - 1389, 1390, 1387, 1384, 1391, 1392, 0, 0, 0, 0, - 1278, 1274, 0, 0, 0, 0, 0, 1180, 1182, 1184, - 0, 923, 922, 1189, 1195, 1198, 1202, 1203, 1204, 1199, - 1200, 1201, 1191, 1192, 1193, 1194, 1196, 1197, 0, 1217, - 0, 1171, 0, 0, 0, 0, 0, 0, 0, 0, - 1316, 1315, 0, 1339, 0, 1104, 1088, 0, 0, 1178, - 1105, 1313, 1323, 1291, 0, 0, 0, 1361, 1360, 983, - 992, 995, 1028, 1029, 999, 1000, 1001, 1005, 1383, 1382, - 1310, 0, 1302, 0, 0, 984, 1009, 1014, 0, 1269, - 1272, 1045, 1271, 0, 1033, 0, 1022, 0, 1031, 1035, - 1010, 1025, 0, 1006, 0, 1303, 1214, 1216, 0, 1212, - 0, 996, 997, 998, 988, 989, 990, 991, 993, 994, - 1002, 1188, 1186, 1187, 0, 1289, 0, 1301, 0, 0, - 1140, 0, 0, 1030, 1307, 0, 853, 660, 853, 0, - 981, 1551, 1380, 1544, 1380, 1533, 1224, 1345, 1379, 0, - 634, 0, 1553, 160, 164, 0, 0, 1290, 194, 196, - 768, 0, 667, 668, 672, 0, 0, 672, 651, 594, - 1980, 1858, 0, 0, 0, 0, 716, 757, 0, 748, - 713, 714, 0, 712, 1352, 717, 1351, 718, 721, 722, - 684, 1340, 758, 760, 0, 753, 0, 1346, 600, 619, - 0, 0, 0, 0, 0, 583, 582, 764, 1528, 1528, - 1530, 1529, 0, 273, 0, 52, 0, 1729, 76, 0, - 0, 0, 0, 0, 0, 295, 72, 73, 0, 397, - 0, 71, 67, 295, 118, 1729, 467, 1729, 467, 1623, - 1692, 1876, 0, 65, 369, 109, 0, 146, 79, 81, - 400, 0, 354, 0, 0, 99, 114, 139, 0, 0, - 54, 244, 258, 263, 142, 267, 264, 1417, 265, 153, - 0, 50, 0, 140, 0, 1415, 0, 0, 56, 144, - 1419, 1567, 1574, 0, 0, 1288, 0, 658, 658, 658, - 656, 657, 1108, 0, 1230, 0, 1232, 1233, 1022, 1427, - 1426, 1428, 1425, 527, 538, 0, 394, 0, 542, 530, - 531, 539, 1395, 227, 0, 218, 395, 0, 0, 395, - 0, 1397, 0, 0, 222, 228, 0, 0, 0, 0, - 0, 393, 385, 383, 416, 0, 390, 384, 0, 0, - 340, 0, 1617, 0, 1697, 201, 206, 0, 0, 0, - 0, 1366, 2149, 2150, 2151, 2152, 2154, 2155, 2156, 2157, - 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167, - 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2177, 2178, - 2179, 2180, 2181, 2182, 515, 0, 518, 864, 1367, 0, - 0, 0, 0, 0, 277, 278, 433, 1378, 435, 0, - 437, 240, 238, 1440, 1568, 1570, 541, 0, 536, 0, - 563, 0, 0, 0, 0, 0, 0, 0, 0, 1118, - 1236, 0, 1255, 1254, 1056, 1063, 1066, 1070, 1071, 1072, - 1256, 0, 0, 0, 1067, 1068, 1069, 1059, 1060, 1061, - 1062, 1064, 1065, 1073, 851, 0, 0, 845, 1265, 1264, - 1258, 1259, 0, 1126, 1127, 1128, 1266, 0, 0, 820, - 689, 691, 688, 0, 0, 853, 647, 647, 647, 647, - 644, 0, 0, 0, 852, 0, 744, 705, 706, 0, - 0, 816, 814, 0, 838, 0, 811, 0, 817, 0, - 802, 0, 809, 858, 825, 0, 0, 827, 1519, 875, - 0, 870, 866, 0, 0, 0, 876, 0, 0, 0, - 0, 0, 0, 0, 1235, 0, 653, 1102, 0, 0, - 0, 1275, 0, 1050, 892, 905, 1027, 0, 1183, 1106, - 0, 1206, 1170, 933, 932, 934, 934, 1051, 0, 1318, - 1320, 0, 0, 0, 0, 1330, 0, 1053, 0, 1224, - 1174, 1176, 1331, 1087, 917, 981, 0, 0, 0, 0, - 0, 0, 0, 1034, 1024, 0, 1032, 1036, 0, 0, - 0, 1018, 0, 0, 1016, 1046, 1012, 0, 0, 1047, - 1288, 0, 1292, 0, 0, 1139, 1148, 771, 767, 727, - 658, 727, 0, 1513, 1535, 1532, 0, 632, 0, 0, - 1554, 0, 183, 0, 0, 0, 0, 0, 186, 200, - 197, 1553, 0, 0, 662, 664, 0, 1207, 672, 666, - 720, 719, 0, 682, 755, 680, 0, 761, 0, 617, - 0, 603, 0, 794, 0, 0, 1522, 1523, 0, 0, - 0, 0, 344, 0, 0, 0, 295, 0, 405, 0, - 412, 0, 0, 397, 376, 69, 68, 98, 0, 0, - 0, 61, 117, 90, 82, 57, 96, 0, 0, 101, - 0, 94, 111, 112, 110, 115, 0, 305, 330, 0, - 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1574, 1560, 1573, 1289, 1289, - 1285, 0, 0, 0, 660, 1109, 0, 526, 568, 565, - 566, 0, 564, 249, 570, 404, 0, 0, 0, 216, - 392, 0, 0, 1412, 500, 503, 1394, 430, 0, 227, - 0, 231, 0, 0, 218, 395, 0, 368, 378, 379, - 364, 391, 362, 361, 363, 0, 1618, 242, 0, 1612, - 0, 208, 204, 395, 1411, 0, 0, 517, 0, 520, - 863, 507, 0, 512, 0, 0, 510, 0, 1406, 276, - 467, 1572, 551, 556, 0, 562, 558, 557, 552, 560, - 559, 555, 1119, 1130, 1253, 0, 0, 0, 0, 844, - 847, 0, 1125, 1120, 818, 0, 0, 727, 0, 0, - 0, 0, 638, 637, 643, 0, 0, 1142, 0, 708, - 813, 0, 0, 0, 800, 789, 795, 796, 0, 0, - 0, 856, 855, 826, 879, 0, 859, 879, 0, 879, - 877, 0, 0, 886, 974, 975, 976, 977, 978, 979, - 980, 911, 0, 1277, 1273, 1179, 1181, 1218, 929, 927, - 1052, 1321, 1314, 1317, 1223, 1325, 1327, 0, 0, 0, - 0, 1338, 0, 1173, 1339, 1359, 985, 0, 0, 1015, - 1270, 1037, 0, 0, 0, 1011, 1206, 0, 0, 0, - 0, 0, 1020, 0, 1296, 1289, 0, 1295, 0, 0, - 0, 0, 1114, 772, 744, 0, 744, 0, 1281, 0, - 628, 630, 633, 169, 1552, 0, 1547, 161, 162, 163, - 0, 0, 0, 178, 155, 0, 0, 0, 195, 183, - 171, 670, 671, 0, 665, 681, 1341, 1347, 602, 0, - 1084, 0, 0, 599, 0, 274, 147, 295, 0, 0, - 75, 0, 414, 356, 406, 389, 371, 0, 0, 0, - 296, 0, 431, 0, 0, 377, 0, 0, 0, 0, - 357, 0, 0, 316, 0, 0, 389, 0, 396, 312, - 313, 0, 60, 91, 0, 87, 0, 116, 0, 0, - 0, 0, 0, 63, 86, 0, 58, 864, 467, 467, - 66, 1372, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, - 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, - 2050, 2051, 2169, 2052, 302, 2053, 1800, 2054, 2055, 2056, - 2057, 2058, 0, 2059, 862, 2060, 2061, 2249, 2062, 2063, - 1191, 1192, 301, 300, 399, 297, 407, 299, 0, 1373, - 298, 402, 355, 0, 0, 143, 1418, 0, 141, 0, - 1416, 150, 148, 145, 1420, 1559, 0, 0, 1112, 1113, - 1110, 658, 0, 0, 0, 0, 545, 533, 0, 0, - 0, 1617, 203, 0, 0, 1729, 0, 0, 230, 229, - 219, 0, 1412, 215, 392, 0, 422, 340, 864, 417, - 0, 1617, 1615, 0, 0, 209, 0, 207, 1412, 1611, - 499, 502, 516, 519, 0, 0, 0, 0, 585, 504, - 0, 0, 0, 438, 561, 1076, 0, 0, 0, 0, - 698, 0, 704, 744, 642, 641, 640, 639, 726, 1666, - 1963, 1857, 0, 730, 725, 728, 733, 735, 734, 736, - 732, 743, 0, 746, 707, 837, 1219, 1221, 0, 0, - 0, 0, 801, 803, 0, 805, 0, 857, 873, 0, - 874, 0, 872, 878, 867, 1276, 1319, 1328, 1329, 1324, - 1333, 1335, 0, 0, 0, 982, 1054, 1043, 1041, 1038, - 0, 1039, 1019, 0, 0, 1017, 1013, 0, 1048, 0, - 0, 1293, 0, 1134, 0, 1137, 1151, 1147, 1146, 1142, - 1109, 1142, 1514, 626, 629, 0, 182, 159, 185, 184, - 0, 1290, 192, 0, 0, 183, 0, 494, 495, 496, - 183, 0, 187, 523, 0, 0, 614, 793, 607, 608, - 0, 410, 77, 0, 389, 0, 295, 373, 372, 375, - 370, 374, 0, 432, 0, 0, 314, 0, 321, 359, - 360, 358, 315, 389, 395, 317, 0, 0, 0, 83, - 62, 59, 64, 84, 0, 0, 85, 88, 858, 100, - 93, 1372, 0, 0, 0, 78, 80, 0, 0, 1287, - 1286, 0, 529, 528, 567, 569, 525, 534, 249, 0, - 0, 0, 364, 1614, 0, 0, 0, 392, 0, 232, - 0, 0, 0, 1617, 0, 0, 292, 0, 337, 0, - 235, 1616, 202, 205, 0, 0, 0, 1603, 521, 522, - 0, 0, 1404, 1405, 0, 1077, 0, 1078, 848, 0, - 0, 696, 1142, 0, 0, 0, 737, 731, 0, 1141, - 1143, 0, 693, 1222, 797, 0, 799, 0, 823, 0, - 823, 806, 868, 860, 1326, 1336, 1337, 1332, 1132, 0, - 1040, 1044, 1042, 1021, 1289, 1289, 1297, 1294, 1136, 1150, - 1153, 746, 1357, 746, 631, 625, 0, 0, 170, 0, - 0, 167, 154, 473, 0, 497, 471, 172, 1208, 604, - 605, 0, 295, 0, 388, 411, 326, 304, 0, 0, - 0, 311, 318, 421, 320, 0, 92, 108, 0, 0, - 401, 151, 149, 1111, 545, 0, 221, 1412, 340, 1611, - 0, 0, 0, 0, 364, 242, 1613, 353, 346, 347, - 348, 349, 350, 351, 352, 367, 366, 338, 339, 210, - 0, 0, 0, 0, 505, 1406, 0, 189, 198, 0, - 189, 1079, 699, 0, 746, 0, 0, 0, 729, 0, - 0, 745, 0, 590, 1220, 0, 788, 786, 0, 787, - 1334, 0, 0, 0, 0, 660, 693, 693, 156, 0, - 157, 193, 0, 0, 0, 0, 0, 492, 395, 413, - 387, 0, 380, 324, 323, 325, 329, 0, 327, 0, - 343, 0, 336, 304, 0, 95, 0, 408, 524, 532, - 0, 294, 1605, 392, 0, 220, 1611, 340, 1617, 1611, - 0, 1608, 0, 0, 0, 0, 191, 1412, 0, 191, - 0, 693, 739, 0, 738, 1145, 1144, 695, 798, 0, - 1133, 1299, 1298, 0, 1157, 589, 588, 0, 0, 0, - 0, 472, 0, 0, 473, 421, 0, 365, 0, 0, - 326, 0, 319, 418, 419, 420, 0, 332, 322, 333, - 89, 107, 409, 0, 392, 1606, 293, 236, 1604, 1609, - 1610, 0, 189, 188, 669, 190, 853, 199, 669, 703, - 591, 740, 692, 804, 1152, 0, 0, 0, 0, 0, - 166, 853, 177, 0, 481, 0, 488, 164, 164, 489, - 490, 491, 0, 336, 386, 381, 303, 328, 342, 0, - 0, 0, 334, 0, 335, 1611, 0, 191, 672, 1402, - 672, 1949, 1667, 1914, 0, 1169, 1158, 1169, 1169, 1149, - 158, 165, 0, 485, 486, 487, 0, 0, 477, 0, - 0, 480, 0, 295, 308, 0, 307, 0, 398, 331, - 1607, 1412, 669, 179, 180, 0, 1162, 1161, 1160, 1164, - 1163, 0, 1156, 1154, 1155, 853, 484, 0, 476, 483, - 0, 479, 478, 493, 415, 306, 310, 309, 853, 672, - 0, 0, 1166, 0, 1167, 176, 474, 0, 1403, 181, - 1159, 1165, 1168, 0, 482 + 0, 0, 1577, 1576, 0, 1568, 1294, 1299, 666, 666, + 666, 0, 0, 0, 0, 664, 665, 0, 0, 0, + 0, 0, 545, 397, 409, 0, 0, 0, 1407, 222, + 0, 0, 0, 0, 0, 0, 0, 436, 1410, 1408, + 1406, 1409, 1411, 0, 0, 0, 0, 0, 214, 217, + 0, 396, 362, 0, 0, 0, 0, 1422, 0, 0, + 514, 512, 515, 504, 517, 507, 0, 1739, 386, 1419, + 0, 1573, 0, 0, 275, 473, 1387, 0, 470, 473, + 1353, 0, 473, 241, 0, 0, 1455, 1499, 251, 271, + 252, 272, 551, 1579, 1581, 0, 554, 559, 543, 0, + 543, 0, 556, 560, 543, 555, 0, 543, 550, 0, + 1141, 0, 1131, 0, 0, 848, 0, 0, 1132, 1067, + 1068, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1085, + 1084, 1133, 852, 0, 855, 0, 0, 1270, 1271, 0, + 1134, 0, 0, 1277, 0, 0, 0, 1139, 0, 790, + 0, 0, 691, 692, 700, 696, 703, 0, 706, 693, + 642, 592, 1729, 1770, 0, 653, 653, 653, 651, 641, + 0, 733, 791, 0, 781, 0, 0, 0, 814, 0, + 0, 816, 818, 0, 0, 821, 0, 797, 796, 0, + 0, 780, 0, 0, 860, 0, 1358, 0, 0, 213, + 0, 0, 0, 0, 889, 0, 0, 878, 0, 881, + 877, 871, 0, 971, 972, 973, 974, 975, 976, 977, + 978, 979, 980, 981, 982, 983, 895, 1395, 0, 901, + 1398, 0, 1399, 1400, 1397, 1394, 1401, 1402, 0, 0, + 0, 0, 1288, 1284, 0, 0, 0, 0, 0, 1190, + 1192, 1194, 0, 933, 932, 1199, 1205, 1208, 1212, 1213, + 1214, 1209, 1210, 1211, 1201, 1202, 1203, 1204, 1206, 1207, + 0, 1227, 0, 1181, 0, 0, 0, 0, 0, 0, + 0, 0, 1326, 1325, 0, 1349, 0, 1114, 1098, 0, + 0, 1188, 1115, 1323, 1333, 1301, 0, 0, 0, 1371, + 1370, 993, 1002, 1005, 1038, 1039, 1009, 1010, 1011, 1015, + 1393, 1392, 1320, 0, 1312, 0, 0, 994, 1019, 1024, + 0, 1279, 1282, 1055, 1281, 0, 1043, 0, 1032, 0, + 1041, 1045, 1020, 1035, 0, 1016, 0, 1313, 1224, 1226, + 0, 1222, 0, 1006, 1007, 1008, 998, 999, 1000, 1001, + 1003, 1004, 1012, 1198, 1196, 1197, 0, 1299, 0, 1311, + 0, 0, 1150, 0, 0, 1040, 1317, 0, 859, 666, + 859, 0, 991, 1561, 1390, 1554, 1390, 1543, 1234, 1355, + 1389, 0, 640, 0, 1563, 160, 164, 0, 0, 1300, + 194, 196, 774, 0, 673, 674, 678, 0, 0, 678, + 657, 600, 1990, 1868, 0, 0, 0, 0, 722, 763, + 0, 754, 719, 720, 0, 718, 1362, 723, 1361, 724, + 727, 728, 690, 1350, 764, 766, 0, 759, 0, 1356, + 606, 625, 0, 0, 0, 0, 0, 589, 588, 770, + 1538, 1538, 1540, 1539, 0, 273, 0, 52, 0, 1739, + 76, 0, 0, 0, 0, 0, 0, 295, 72, 73, + 0, 401, 0, 71, 67, 295, 118, 1739, 473, 1739, + 473, 1633, 1702, 1886, 0, 65, 373, 109, 0, 146, + 79, 81, 408, 404, 0, 354, 0, 0, 99, 114, + 139, 0, 0, 54, 244, 258, 263, 142, 267, 264, + 1427, 265, 153, 0, 50, 0, 140, 0, 1425, 0, + 0, 56, 144, 1429, 1577, 1584, 0, 0, 1298, 0, + 664, 664, 664, 662, 663, 1118, 0, 1240, 0, 1242, + 1243, 1032, 1437, 1436, 1438, 1435, 533, 544, 0, 398, + 0, 548, 536, 537, 545, 1405, 227, 0, 218, 399, + 0, 0, 399, 0, 1407, 0, 0, 222, 228, 0, + 0, 0, 0, 0, 397, 389, 387, 422, 0, 394, + 388, 368, 0, 1627, 0, 1707, 201, 206, 0, 0, + 0, 0, 1376, 2159, 2160, 2161, 2162, 2164, 2165, 2166, + 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, + 2177, 2178, 2179, 2180, 2181, 2182, 2183, 2184, 2185, 2187, + 2188, 2189, 2190, 2191, 2192, 521, 0, 524, 870, 1377, + 0, 0, 0, 0, 0, 277, 278, 439, 1388, 441, + 0, 443, 240, 238, 1450, 1578, 1580, 547, 0, 542, + 0, 569, 0, 0, 0, 0, 0, 0, 0, 0, + 1128, 1246, 0, 1265, 1264, 1066, 1073, 1076, 1080, 1081, + 1082, 1266, 0, 0, 0, 1077, 1078, 1079, 1069, 1070, + 1071, 1072, 1074, 1075, 1083, 857, 0, 0, 851, 1275, + 1274, 1268, 1269, 0, 1136, 1137, 1138, 1276, 0, 0, + 826, 695, 697, 694, 0, 0, 859, 653, 653, 653, + 653, 650, 0, 0, 0, 858, 0, 750, 711, 712, + 0, 0, 822, 820, 0, 844, 0, 817, 0, 823, + 0, 808, 0, 815, 864, 831, 0, 0, 833, 1529, + 885, 0, 880, 879, 872, 0, 0, 0, 0, 886, + 0, 0, 0, 0, 0, 0, 0, 1245, 0, 659, + 1112, 0, 0, 0, 1285, 0, 1060, 902, 915, 1037, + 0, 1193, 1116, 0, 1216, 1180, 943, 942, 944, 944, + 1061, 0, 1328, 1330, 0, 0, 0, 0, 1340, 0, + 1063, 0, 1234, 1184, 1186, 1341, 1097, 927, 991, 0, + 0, 0, 0, 0, 0, 0, 1044, 1034, 0, 1042, + 1046, 0, 0, 0, 1028, 0, 0, 1026, 1056, 1022, + 0, 0, 1057, 1298, 0, 1302, 0, 0, 1149, 1158, + 777, 773, 733, 664, 733, 0, 1523, 1545, 1542, 0, + 638, 0, 0, 1564, 0, 183, 0, 0, 0, 0, + 0, 186, 200, 197, 1563, 0, 0, 668, 670, 0, + 1217, 678, 672, 726, 725, 0, 688, 761, 686, 0, + 767, 0, 623, 0, 609, 0, 800, 0, 0, 1532, + 1533, 0, 0, 0, 0, 344, 0, 0, 0, 295, + 0, 411, 0, 418, 0, 0, 401, 380, 69, 68, + 98, 0, 0, 0, 61, 117, 90, 82, 57, 96, + 0, 0, 101, 0, 94, 111, 112, 110, 115, 0, + 305, 330, 0, 0, 0, 341, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1584, + 1570, 1583, 1299, 1299, 1295, 0, 0, 0, 666, 1119, + 0, 532, 574, 571, 572, 0, 570, 249, 576, 410, + 0, 0, 0, 216, 396, 0, 0, 1422, 506, 509, + 1404, 436, 0, 227, 0, 231, 0, 0, 218, 399, + 0, 372, 382, 383, 362, 395, 0, 0, 0, 0, + 361, 340, 242, 0, 1622, 0, 208, 204, 399, 1421, + 0, 0, 523, 0, 526, 869, 513, 0, 518, 0, + 0, 516, 0, 1416, 276, 473, 1582, 557, 562, 0, + 568, 564, 563, 558, 566, 565, 561, 1129, 1140, 1263, + 0, 0, 0, 0, 850, 853, 0, 1135, 1130, 824, + 0, 0, 733, 0, 0, 0, 0, 644, 643, 649, + 0, 0, 1152, 0, 714, 819, 0, 0, 0, 806, + 795, 801, 802, 0, 0, 0, 862, 861, 832, 889, + 0, 0, 865, 889, 0, 889, 0, 887, 0, 0, + 896, 984, 985, 986, 987, 988, 989, 990, 921, 0, + 1287, 1283, 1189, 1191, 1228, 939, 937, 1062, 1331, 1324, + 1327, 1233, 1335, 1337, 0, 0, 0, 0, 1348, 0, + 1183, 1349, 1369, 995, 0, 0, 1025, 1280, 1047, 0, + 0, 0, 1021, 1216, 0, 0, 0, 0, 0, 1030, + 0, 1306, 1299, 0, 1305, 0, 0, 0, 0, 1124, + 778, 750, 0, 750, 0, 1291, 0, 634, 636, 639, + 169, 1562, 0, 1557, 161, 162, 163, 0, 0, 0, + 178, 155, 0, 0, 0, 195, 183, 171, 676, 677, + 0, 671, 687, 1351, 1357, 608, 0, 1094, 0, 0, + 605, 0, 274, 147, 295, 0, 0, 75, 0, 420, + 356, 412, 393, 375, 0, 0, 0, 296, 0, 437, + 0, 0, 381, 0, 0, 0, 0, 357, 0, 0, + 316, 0, 0, 393, 0, 400, 312, 313, 0, 60, + 91, 0, 87, 0, 116, 0, 0, 0, 0, 0, + 63, 86, 0, 58, 870, 473, 473, 66, 407, 403, + 406, 355, 0, 0, 143, 1428, 0, 141, 0, 1426, + 150, 148, 145, 1430, 1569, 0, 0, 1122, 1123, 1120, + 664, 0, 0, 0, 0, 551, 539, 0, 0, 0, + 1627, 203, 0, 0, 1739, 0, 0, 230, 229, 219, + 0, 1422, 215, 396, 0, 428, 368, 870, 423, 0, + 0, 366, 365, 367, 0, 1628, 1627, 1625, 0, 0, + 209, 0, 207, 1422, 1621, 505, 508, 522, 525, 0, + 0, 0, 0, 591, 510, 0, 0, 0, 444, 567, + 1086, 0, 0, 0, 0, 704, 0, 710, 750, 648, + 647, 646, 645, 732, 1676, 1973, 1867, 0, 736, 731, + 734, 739, 741, 740, 742, 738, 749, 0, 752, 713, + 843, 1229, 1231, 0, 0, 0, 0, 807, 809, 0, + 811, 0, 863, 883, 0, 0, 884, 0, 882, 874, + 888, 873, 1286, 1329, 1338, 1339, 1334, 1343, 1345, 0, + 0, 0, 992, 1064, 1053, 1051, 1048, 0, 1049, 1029, + 0, 0, 1027, 1023, 0, 1058, 0, 0, 1303, 0, + 1144, 0, 1147, 1161, 1157, 1156, 1152, 1119, 1152, 1524, + 632, 635, 0, 182, 159, 185, 184, 0, 1300, 192, + 0, 0, 183, 0, 500, 501, 502, 183, 0, 187, + 529, 0, 0, 620, 799, 613, 614, 0, 416, 77, + 0, 393, 0, 295, 377, 376, 379, 374, 378, 0, + 438, 0, 0, 314, 0, 321, 359, 360, 358, 315, + 393, 399, 317, 0, 0, 0, 83, 62, 59, 64, + 84, 0, 0, 85, 88, 864, 100, 93, 0, 78, + 80, 0, 0, 1297, 1296, 0, 535, 534, 573, 575, + 531, 540, 249, 0, 0, 0, 362, 1624, 0, 0, + 0, 396, 0, 232, 0, 0, 0, 1627, 0, 0, + 340, 0, 0, 0, 235, 1626, 202, 205, 0, 0, + 0, 1613, 527, 528, 0, 0, 1414, 1415, 0, 1087, + 0, 1088, 854, 0, 0, 702, 1152, 0, 0, 0, + 743, 737, 0, 1151, 1153, 0, 699, 1232, 803, 0, + 805, 0, 829, 0, 829, 812, 876, 875, 866, 1336, + 1346, 1347, 1342, 1142, 0, 1050, 1054, 1052, 1031, 1299, + 1299, 1307, 1304, 1146, 1160, 1163, 752, 1367, 752, 637, + 631, 0, 0, 170, 0, 0, 167, 154, 479, 0, + 503, 477, 172, 1218, 610, 611, 0, 295, 0, 392, + 417, 326, 304, 0, 0, 0, 311, 318, 427, 320, + 0, 92, 108, 1382, 2042, 2043, 2044, 2045, 2046, 2047, + 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, + 2058, 2059, 2060, 2061, 2179, 2062, 302, 2063, 1810, 2064, + 2065, 2066, 2067, 2068, 0, 2069, 868, 2070, 2071, 2259, + 2072, 2073, 1201, 1202, 301, 300, 405, 297, 413, 299, + 0, 1383, 298, 151, 149, 1121, 551, 0, 221, 1422, + 368, 1621, 0, 0, 0, 0, 362, 242, 1623, 353, + 346, 347, 348, 349, 350, 351, 352, 371, 370, 292, + 0, 0, 0, 337, 0, 210, 0, 0, 0, 0, + 511, 1416, 0, 189, 198, 0, 189, 1089, 705, 0, + 752, 0, 0, 0, 735, 0, 0, 751, 0, 596, + 1230, 0, 794, 792, 0, 793, 1344, 0, 0, 0, + 0, 666, 699, 699, 156, 0, 157, 193, 0, 0, + 0, 0, 0, 498, 399, 419, 391, 0, 384, 324, + 323, 325, 329, 0, 327, 0, 343, 0, 336, 304, + 0, 95, 0, 0, 530, 538, 0, 340, 1615, 396, + 0, 220, 1621, 368, 1627, 363, 364, 338, 339, 1621, + 0, 1618, 0, 0, 0, 0, 191, 1422, 0, 191, + 0, 699, 745, 0, 744, 1155, 1154, 701, 804, 0, + 1143, 1309, 1308, 0, 1167, 595, 594, 0, 0, 0, + 0, 478, 0, 0, 479, 427, 0, 369, 0, 0, + 326, 0, 319, 424, 425, 426, 0, 332, 322, 333, + 89, 107, 0, 0, 0, 294, 396, 1616, 340, 236, + 1614, 1619, 1620, 0, 189, 188, 675, 190, 859, 199, + 675, 709, 597, 746, 698, 810, 1162, 0, 0, 0, + 0, 0, 166, 859, 177, 0, 487, 0, 494, 164, + 164, 495, 496, 497, 0, 336, 390, 385, 303, 328, + 342, 0, 0, 0, 334, 0, 335, 0, 414, 1621, + 293, 0, 191, 678, 1412, 678, 1959, 1677, 1924, 0, + 1179, 1168, 1179, 1179, 1159, 158, 165, 0, 491, 492, + 493, 0, 0, 483, 0, 0, 486, 0, 295, 308, + 0, 307, 0, 402, 331, 415, 1617, 1422, 675, 179, + 180, 0, 1172, 1171, 1170, 1174, 1173, 0, 1166, 1164, + 1165, 859, 490, 0, 482, 489, 0, 485, 484, 499, + 421, 306, 310, 309, 859, 678, 0, 0, 1176, 0, + 1177, 176, 480, 0, 1413, 181, 1169, 1175, 1178, 0, + 488 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 47, 48, 49, 769, 2773, 2774, 2775, 2352, 2341, - 2342, 1819, 1820, 1251, 3615, 2353, 1252, 1253, 2777, 770, + -1, 47, 48, 49, 769, 2776, 2777, 2778, 2354, 2343, + 2344, 1819, 1820, 1251, 3631, 2355, 1252, 1253, 2780, 770, 821, 1191, 870, 1129, 1666, 935, 1288, 1289, 771, 1826, - 772, 3023, 2264, 2715, 3594, 54, 3322, 2268, 1205, 3325, - 3558, 3016, 3320, 2717, 3636, 3694, 3323, 2269, 2270, 3559, - 2271, 773, 2455, 3206, 3207, 774, 775, 1918, 58, 1353, - 561, 1915, 3188, 2841, 2842, 776, 777, 1388, 1389, 990, - 778, 1919, 1858, 3143, 1271, 1848, 1403, 62, 63, 1944, - 779, 109, 931, 65, 780, 2760, 3144, 3608, 2788, 3768, - 3078, 3079, 3605, 3606, 2763, 2355, 3677, 3678, 2856, 1839, - 3672, 2442, 3545, 2361, 2335, 3080, 2450, 3504, 3196, 2356, - 3060, 2848, 2849, 2443, 3601, 1939, 2444, 3602, 3346, 2445, - 1894, 1922, 2764, 3679, 2362, 1895, 2759, 3145, 1823, 2446, - 3612, 2447, 562, 3064, 781, 759, 760, 982, 1382, 761, - 782, 3596, 3759, 3789, 3719, 3754, 3327, 3664, 3328, 3329, - 3330, 783, 1930, 1931, 1932, 1933, 1934, 1935, 966, 1936, - 2495, 2496, 784, 785, 2817, 2421, 3398, 3399, 2519, 2415, - 1412, 1897, 1413, 551, 1978, 2823, 786, 1130, 74, 75, - 1037, 76, 3340, 77, 78, 1793, 1794, 1795, 872, 882, - 883, 1746, 3009, 3010, 2709, 1498, 2049, 875, 1211, 1762, - 856, 857, 1883, 899, 1886, 1757, 1758, 2274, 2724, 1786, - 1787, 1220, 1221, 2035, 2036, 3573, 2037, 2038, 1491, 1492, - 3441, 2589, 2590, 1502, 1774, 1778, 1779, 2295, 2285, 1765, - 2586, 3243, 3244, 3245, 3246, 3247, 3248, 3249, 1131, 2917, - 3452, 1782, 1783, 1223, 1224, 1225, 1791, 2305, 80, 81, - 2246, 2697, 2698, 827, 828, 3261, 1522, 1796, 2923, 2924, - 2925, 3264, 3265, 3266, 829, 1032, 1033, 1060, 1055, 1511, - 2061, 830, 831, 2012, 2013, 2557, 1062, 2051, 2073, 2074, - 2931, 2614, 1591, 2338, 1592, 1593, 2087, 1594, 1132, 1595, - 1623, 1133, 1628, 1597, 1134, 1135, 1136, 1600, 1137, 1138, - 1139, 1140, 1616, 1141, 1142, 1641, 2091, 2092, 2093, 2094, + 772, 3030, 2266, 2718, 3610, 54, 3289, 2270, 1205, 3292, + 3574, 3023, 3287, 2720, 3656, 3716, 3290, 2271, 2272, 3575, + 2273, 773, 2456, 3171, 3172, 774, 775, 1918, 58, 1353, + 561, 1915, 3147, 2845, 2846, 776, 777, 1388, 1389, 990, + 778, 1919, 1858, 3525, 1271, 1848, 1403, 62, 63, 1944, + 779, 109, 931, 65, 780, 2763, 3526, 3624, 2791, 3793, + 3085, 3086, 3621, 3622, 2766, 2357, 3697, 3698, 3165, 1839, + 3692, 2445, 3557, 2364, 2337, 3087, 2451, 2860, 2861, 3469, + 3155, 2358, 3067, 2852, 2853, 2446, 3617, 1939, 2447, 3618, + 3313, 2448, 1894, 1922, 2767, 3699, 2365, 1895, 2762, 3527, + 1823, 2449, 3628, 2450, 562, 3071, 781, 759, 760, 982, + 1382, 761, 782, 3612, 3784, 3815, 3741, 3779, 3294, 3684, + 3295, 3296, 3297, 783, 1930, 1931, 1932, 1933, 1934, 1935, + 966, 1936, 2496, 2497, 784, 785, 2821, 2424, 3362, 3363, + 2520, 2418, 1412, 1897, 1413, 551, 1978, 2827, 786, 1130, + 74, 75, 1037, 76, 3307, 77, 78, 1793, 1794, 1795, + 872, 882, 883, 1746, 3016, 3017, 2712, 1498, 2049, 875, + 1211, 1762, 856, 857, 1883, 899, 1886, 1757, 1758, 2276, + 2727, 1786, 1787, 1220, 1221, 2035, 2036, 3589, 2037, 2038, + 1491, 1492, 3405, 2590, 2591, 1502, 1774, 1778, 1779, 2297, + 2287, 1765, 2587, 3208, 3209, 3210, 3211, 3212, 3213, 3214, + 1131, 2922, 3416, 1782, 1783, 1223, 1224, 1225, 1791, 2307, + 80, 81, 2248, 2700, 2701, 827, 828, 3226, 1522, 1796, + 2928, 2929, 2930, 3229, 3230, 3231, 829, 1032, 1033, 1060, + 1055, 1511, 2061, 830, 831, 2012, 2013, 2558, 1062, 2051, + 2073, 2074, 2936, 2616, 1591, 2340, 1592, 1593, 2089, 1594, + 1132, 1595, 1623, 1133, 1628, 1597, 1134, 1135, 1136, 1600, + 1137, 1138, 1139, 1140, 1616, 1141, 1142, 1641, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, - 1192, 1797, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, - 1152, 1153, 833, 1154, 1155, 1717, 2240, 2696, 3253, 3449, - 3450, 3002, 3308, 3480, 3585, 3708, 3745, 3746, 3782, 1156, - 1157, 1661, 1662, 1663, 2127, 2128, 2129, 2130, 2234, 1711, - 1712, 1158, 3147, 1714, 2150, 3257, 3258, 1193, 1484, 1654, - 1333, 1334, 1605, 1458, 1459, 1465, 1987, 1473, 1477, 2017, - 2018, 1485, 2201, 1159, 2120, 2121, 2632, 1618, 3011, 1160, - 1287, 1667, 2997, 2237, 1715, 2194, 1167, 1161, 1168, 1163, - 1650, 2970, 2650, 2651, 1651, 2655, 2966, 2967, 2163, 2971, - 3281, 3282, 2657, 2302, 1743, 2307, 2308, 986, 1164, 1165, - 1166, 1335, 535, 1606, 3695, 1378, 1198, 1336, 2190, 787, - 1067, 2113, 788, 1350, 1910, 789, 3433, 3222, 1367, 1940, - 2459, 563, 790, 791, 544, 87, 2410, 947, 88, 89, - 90, 908, 1405, 792, 996, 1407, 997, 91, 1408, 999, - 1000, 794, 864, 865, 1531, 1731, 1532, 795, 94, 839, - 1806, 796, 1187, 879, 1188, 1190, 797, 1208, 2712, 2262, - 97, 98, 99, 119, 1283, 2515, 1964, 1965, 1875, 798, - 850, 851, 888, 102, 103, 1236, 852, 800, 801, 3427, - 802, 2859, 1359, 545, 537, 538, 1608, 733, 1338, 734 + 2105, 2106, 1192, 1797, 1144, 1145, 1146, 1147, 1148, 1149, + 1150, 1151, 1152, 1153, 833, 1154, 1155, 1717, 2242, 2699, + 3218, 3413, 3414, 3009, 3275, 3445, 3601, 3730, 3770, 3771, + 3808, 1156, 1157, 1661, 1662, 1663, 2129, 2130, 2131, 2132, + 2236, 1711, 1712, 1158, 3529, 1714, 2152, 3222, 3223, 1193, + 1484, 1654, 1333, 1334, 1605, 1458, 1459, 1465, 1987, 1473, + 1477, 2017, 2018, 1485, 2203, 1159, 2122, 2123, 2635, 1618, + 3018, 1160, 1287, 1667, 3004, 2239, 1715, 2196, 1167, 1161, + 1168, 1163, 1650, 2977, 2653, 2654, 1651, 2658, 2973, 2974, + 2165, 2978, 3248, 3249, 2660, 2304, 1743, 2309, 2310, 986, + 1164, 1165, 1166, 1335, 535, 1606, 3717, 1378, 1198, 1336, + 2192, 787, 1067, 2115, 788, 1350, 1910, 789, 3397, 3187, + 1367, 1940, 2460, 563, 790, 791, 544, 87, 2413, 947, + 88, 89, 90, 908, 1405, 792, 996, 1407, 997, 91, + 1408, 999, 1000, 794, 864, 865, 1531, 1731, 1532, 795, + 94, 839, 1806, 796, 1187, 879, 1188, 1190, 797, 1208, + 2715, 2264, 97, 98, 99, 119, 1283, 2516, 1964, 1965, + 1875, 798, 850, 851, 888, 102, 103, 1236, 852, 800, + 801, 3391, 802, 2864, 1359, 545, 537, 538, 1608, 733, + 1338, 734 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -3295 +#define YYPACT_NINF -3336 static const int yypact[] = { - 7837, 387, 787, -3295, -3295, 708, 387, 53010, 69762, 148, - 387, 124, 3023, 55540, -3295, -3295, 49956, 3804, 387, 59582, - 76838, 461, 467, 34057, 552, 60091, -3295, -3295, -3295, 69762, - 59582, 60600, 387, 353, 70271, -3295, 387, 37113, 56049, 525, - -3295, 59582, 92, 297, 61109, 59582, 4028, 888, 445, -3295, - -3295, -3295, -3295, -3295, 323, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, 185, -3295, 134, 214, 34057, 34057, 955, - 449, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, 546, -3295, -3295, 838, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, 36603, -3295, -3295, -3295, -3295, -3295, -3295, - 70780, 61618, 59582, 62127, 56558, 62636, -3295, 827, 707, 1115, - 841, 181, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, 201, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, 634, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, 225, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, 565, -3295, 665, -3295, 226, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, 145, -3295, -3295, 1091, - 2223, 59582, 411, 519, 885, -3295, 63145, -3295, 880, -3295, - -3295, 898, 963, 1049, -3295, -3295, 57067, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, 50465, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, 1013, -3295, -3295, 829, -3295, - 270, -3295, -3295, 866, 819, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, 922, -3295, -3295, -3295, 925, 71289, - 63654, 64163, -3295, 812, 711, 987, 6452, 76856, 33037, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, 546, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, 60091, 69762, 824, 836, 1189, 840, 35075, - 844, 37623, 857, 863, 1241, 899, 914, 927, 941, 297, - 33547, 950, 565, 1472, 64672, 64672, -36, 34566, 2495, -3295, - 64672, 65181, -3295, 980, -3295, 1115, -3295, -3295, -3295, -3295, - 395, 968, -3295, 65690, 65690, 65690, 1000, 1287, 65690, -3295, - -3295, -3295, 1007, -3295, -3295, 1236, 21003, 21003, 71798, 71798, - 1115, 71798, 1031, 71798, -3295, -3295, 374, 841, -3295, 565, - -3295, -3295, 955, -3295, -3295, 56049, -3295, -3295, 292, 1375, - 21003, 59582, 1014, -3295, 1035, 1014, 1041, 1061, 1066, -3295, - 7837, 1404, 1299, 1381, 57576, 370, 370, 1537, 370, 786, - 923, 4316, 2204, -3295, 1297, -3295, 1098, -3295, 59582, 60091, - 1200, 1460, 1129, 1417, -3295, -3295, 1491, 1331, 1502, 773, - 1346, 1560, 6505, 1565, 1090, 1567, 1123, 1598, 1552, 1713, - 41, -3295, 21003, 50974, 565, -3295, 12479, 21003, -3295, -3295, - -3295, 1333, -3295, -3295, -3295, -3295, -3295, 59582, 69762, 1246, - 1237, -3295, -3295, -3295, -3295, 1709, 1497, -3295, 72307, -3295, - -3295, 1309, 66199, 66708, 67217, 67726, 68235, 1702, -3295, -3295, - 1650, -3295, -3295, -3295, 1301, -3295, -3295, -3295, 199, 72816, - 1653, 1306, 123, -3295, 1684, 245, -3295, 1686, 1536, 15129, - -3295, 1489, -3295, -3295, -3295, 297, -3295, 626, -3295, -3295, - 46910, -3295, -3295, 76856, 1419, 1350, -3295, 21003, 21003, 1356, - 5835, 64672, 65181, 21003, 59582, -3295, 21003, 26343, 1357, 21003, - 21003, 13013, 21003, 31027, 64672, 2495, 1358, -3295, 710, -3295, - 59582, 1363, -3295, 1464, 1464, 353, 34057, 1675, 33547, 1464, - 1848, 1464, -3295, 919, 1672, 1595, -3295, 34057, 1595, 1138, - 1376, 1678, 1595, -3295, 281, 1681, 1848, 38132, 1379, -3295, - 1464, 1610, -3295, -3295, 21003, 15129, 58085, 1883, -3295, -3295, - -3295, -3295, 1691, -3295, 69762, 1403, -3295, -3295, -3295, -3295, - -3295, -3295, 772, 1920, 174, 1927, 21003, 174, 174, 1407, - 228, 228, -3295, 1607, 1414, -3295, 232, 1418, 1423, 1947, - 1949, 189, 59582, 167, 1008, 174, 21003, -3295, 228, 1427, - 1953, 1431, 1960, 204, 216, -3295, 1438, 234, 21003, 21003, - 21003, 312, 21003, 11411, -3295, 50974, 1961, 59582, 263, -3295, - 565, 1441, 1115, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - 1447, -3295, 227, 7043, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, 1483, -3295, -3295, -3295, -3295, 1671, 21003, -3295, - -3295, 1448, 1675, -3295, 237, -3295, -3295, 1675, -3295, -3295, - -3295, -3295, -3295, 255, -3295, 1876, 21003, 21003, -3295, 565, - 73325, -3295, -3295, -3295, -3295, -3295, -3295, -3295, 675, -3295, - 546, 655, 48616, 1450, 1454, 1014, 59582, 59582, 1525, -3295, - -3295, -3295, -3295, 56049, 200, 1781, 56049, 182, 1611, -3295, - -3295, 955, 955, 16197, 1843, 309, 83, 16731, 21537, 1838, - 1719, 236, 913, 1841, -3295, 1723, 1955, 26343, 21003, 21003, - 786, 923, 21003, 1035, 104, -3295, -3295, 59582, -3295, 1779, - 69762, 1580, 59582, 53519, 855, 886, 1494, 1583, 54, 897, - 1930, -3295, 1493, -3295, 1586, 59582, 75855, 252, -3295, 1968, - 252, 252, 264, 1970, 1592, 290, 1765, 1302, -85, 1493, - 2981, -3295, 56049, 161, 1477, 1493, 59582, 1597, 1503, 1493, - 1552, 1115, 69762, 1514, -3295, -3295, 9937, 2016, -3295, -3295, - -3295, 194, 15129, -3295, 1128, 1203, 1492, 1507, -3295, 426, - 209, 1569, 1596, 15129, 1608, 1641, 198, 1646, 1673, 1680, - 1697, 1718, 1724, 1726, 1728, 179, 1730, 1732, 1743, 1750, - 1770, 1772, -3295, 1774, 205, 1786, 239, 1438, 15129, 1788, - -3295, 150, 48616, 32, -3295, -3295, 1801, 221, -3295, 48867, - -3295, 1815, 1605, 1621, 69762, 1557, 59582, 1662, 1202, 1897, - 1966, 1782, -3295, 1867, 59582, 1790, 2981, 1797, 1551, 2031, - 1800, 2041, 1804, 1237, 1805, 1559, -3295, 73834, 50974, -3295, - -3295, -3295, -3295, -3295, 1936, 1918, 69762, 50974, 1561, -3295, - -3295, 69762, -3295, 59582, 59582, -3295, 59582, 69762, -3295, 694, - 48616, 2081, 131, 76856, 51992, -3295, -3295, -3295, -3295, 444, - 562, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - 1115, 50974, -3295, 3327, 47487, 1571, 21003, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, 1572, 1922, - -3295, -3295, 6933, 1577, 47564, 1588, 26343, 26343, 565, 1833, - -3295, -3295, 26343, 1591, 52501, 47434, 1566, 1593, 47821, 17265, - 21003, 17265, 17265, 47958, -3295, 1599, 48010, 64672, 1581, 59582, - 30515, -3295, -3295, -3295, 21003, 21003, 2495, 58579, 1628, 1603, - -3295, 1606, 1464, -3295, 34057, -3295, 34057, -3295, 1899, 34057, - -3295, -3295, 4506, -3295, 34057, 1913, 21003, 34057, -3295, 34057, - 1846, 1859, 1619, 34057, 1464, 59582, 1620, 59582, -3295, -3295, - 48616, -3295, 1622, 727, 1623, -3295, -3295, -3295, -3295, -3295, - -3295, 1679, -3295, -3295, 1679, 1679, -3295, -3295, -3295, -3295, - 1624, 1624, 1634, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, 1639, 1008, -3295, 1679, - -3295, 1624, -3295, -3295, -3295, -3295, -3295, -3295, -3295, 75855, - -3295, -3295, -3295, -3295, 350, 645, -3295, 1640, -3295, -3295, - -3295, 1642, -3295, 1643, 2132, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, 8165, 739, 1624, -3295, -3295, 1975, - -3295, -3295, 21003, 21003, -3295, -3295, 1648, 48616, 1688, -3295, - -3295, 21003, 21003, -3295, -3295, -3295, -3295, 2168, -3295, 196, - 21003, 1679, 1679, -3295, 2991, -3295, 43732, 17799, 1744, 1751, - 2168, -3295, 2168, -3295, 21003, 2991, 2170, 2170, 1660, 38641, - -3295, 1831, 48091, -3295, 1666, 2242, 7772, 1663, -3295, -3295, - 2175, -3295, 1664, 1665, 21003, 45383, 195, 565, 565, 21003, - -3295, 2168, 21003, 6176, 6176, -3295, 210, 58085, 21003, 21003, - 21003, 21003, 21003, 21003, 21003, 21003, 49447, 1761, 223, 69762, - 21003, 21003, 30001, 1677, -3295, 21003, 1916, -3295, 1685, 21003, - 1763, 1079, 21003, 21003, 21003, 21003, 21003, 21003, 21003, 21003, - 21003, -3295, -3295, 29487, 265, 669, 2023, 2049, -31, 421, - 21003, 2042, 12479, -3295, 2042, -3295, -3295, -3295, -3295, -3295, - 238, -3295, -3295, 1622, 1622, 69762, -3295, 59582, 292, 55031, - 21003, -3295, -3295, 1683, 1690, 1988, 2179, 1754, -3295, -3295, - 59582, 1755, -3295, 42204, 2003, -3295, 351, 1692, -3295, 47416, - 1954, 2003, 955, -3295, -3295, 26877, 1828, 1998, 1934, -3295, - -3295, 1914, 1921, -3295, 1700, 48945, 22071, 22071, -3295, 1373, - 48616, 1397, -3295, -3295, -3295, -3295, -3295, -3295, 632, -3295, - 59582, 119, 39150, -3295, 1711, 133, -3295, 2038, 2058, 2024, - 1838, 913, 1716, -3295, 60091, 60091, -3295, -3295, -3295, 1889, - 69762, 1734, 1722, 74343, 59582, 2026, 1976, 2028, -43, 58085, - -3295, 1729, -3295, -3295, -3295, 59582, 69762, 68744, 74852, 51483, - 59582, 2212, 2216, 50974, -3295, -3295, 2224, 2228, -3295, -3295, - 59582, 495, 59582, 6962, -3295, -3295, -3295, -3295, 252, -3295, - -3295, -3295, -3295, -3295, 69762, 59582, -3295, -3295, 252, 69762, - 59582, 252, -3295, 1764, 59582, 59582, 69762, 59582, 1906, 59582, - 59582, 1115, 1713, -3295, 50974, -3295, -3295, 22605, 52, 52, - 1963, 1996, 2002, 1771, 13547, 150, -3295, 21003, 21003, 354, - 336, 69762, 1950, -3295, -3295, 750, 1999, 118, -3295, 69762, - 1813, 59582, 59582, 59582, 59582, 59582, 59582, 1511, -3295, -3295, - -3295, -3295, -3295, 2154, 2306, 1784, 1785, 2156, -3295, 2981, - 2163, 54028, 826, 3313, 2164, 59088, 2167, 1832, 2171, 32045, - -3295, -3295, 1794, -3295, -3295, 1796, 2283, 2050, -3295, -3295, - 2034, -3295, 69762, 2328, -3295, 123, -3295, 50974, -3295, 245, - -3295, 2043, 424, -3295, 15129, 21003, -3295, -3295, -3295, -3295, - -3295, -3295, 1350, 21003, -3295, 778, -3295, -3295, 2295, 1115, - 2295, 536, -3295, -3295, 2295, -3295, 2279, 2295, -3295, 58085, - -3295, 8363, -3295, 21003, 21003, -3295, 21003, 2166, -3295, 2334, - 2334, 58085, 26343, 26343, 26343, 26343, 26343, 26343, 813, 1427, - 26343, 26343, 26343, 26343, 26343, 26343, 26343, 26343, 26343, 27411, - 440, -3295, -3295, 780, 2305, 21003, 21003, 2182, 2166, 21003, - -3295, 58085, 1829, -3295, 1830, 1835, 21003, -3295, 58085, -3295, - 59582, 1836, -3295, -3295, -3295, 27, 1834, 1842, -3295, -3295, - 1675, -3295, 949, 1006, 59582, 1649, 2236, 3005, -3295, -3295, - 21003, 2177, -3295, -22, -3295, 4506, 4506, 34057, -3295, 21003, - 1847, -3295, -3295, 34057, 2192, -3295, 4506, -3295, -3295, 39659, - 4506, -3295, 58085, 788, -3295, 59582, 58085, 810, 21003, -3295, - 15129, 2363, 58085, 2337, 69762, 69762, 2377, 1857, 1860, 1857, - 2168, 1959, -3295, 1964, 1967, 1969, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, 58085, -3295, -3295, 327, - -3295, -3295, -3295, -3295, -3295, -3295, 1861, 1862, 21003, 21003, - 122, -3295, 8444, 1864, 1865, 21003, 48345, -3295, 1869, -3295, - 1866, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, 1878, -3295, - 1884, -3295, 1885, 1901, 1905, 1888, 1891, 8557, 21003, 59582, - -3295, 1900, 23139, 2059, 59582, -3295, -3295, 21003, 21003, 59582, - -3295, 48616, 2277, -3295, 1907, 1909, 8961, -3295, -3295, -3295, - 254, 412, 3909, 421, 4000, 4000, 4000, 2991, -3295, -3295, - -3295, 1924, -3295, 26343, 26343, -3295, 2417, 3326, 11411, -3295, - -3295, -3295, -3295, 2270, -3295, 1056, -3295, 1923, -3295, -3295, - 3371, -3295, 43732, 8191, 21003, 229, -3295, 21003, 30001, 21003, - 2009, 4000, 4000, 4000, 398, 398, 254, 254, 254, 412, - 421, -3295, -3295, -3295, 1925, 21003, 50974, -3295, 1929, 1931, - 2298, 1431, 21003, -3295, -3295, 34057, 1628, 32, 1628, 2168, - 6176, -3295, 1035, -3295, 1035, -3295, 48616, 59582, -3295, 1932, - 583, 34057, 1965, 2420, 2398, 34057, 69762, -3295, -3295, 1937, - 2042, 1956, -3295, -3295, 1957, 21003, 1758, 1957, -3295, 2003, - 34, 2176, 962, 962, 1373, 2178, -3295, -3295, 2011, -3295, - -3295, -3295, 21003, 15663, 1442, -3295, 1446, -3295, -3295, -3295, - -3295, -3295, 1944, -3295, 2219, -3295, 59582, -3295, -3295, 26343, - 2407, 21003, 40168, 2419, 2209, -3295, -3295, -3295, 2005, 2005, - -3295, -3295, 2045, -3295, 2046, 1493, 21003, 2202, -3295, 329, - 1973, 2338, 341, 2286, 69762, -3295, -3295, -3295, 316, 342, - 50974, 1729, -3295, -3295, 224, 2339, 424, 2341, 424, 50974, - 50974, 50974, 815, -3295, -3295, -3295, 1115, -3295, -3295, -3295, - 317, 816, -3295, 1974, 1977, -3295, -3295, -3295, 2056, 1725, - 1493, 2981, -3295, -3295, -3295, -3295, -3295, -3295, -3295, 190, - 1792, 1493, 2064, -3295, 2068, -3295, 2071, 1935, 1493, -3295, - -3295, 1713, 1514, 830, 18333, 48616, 208, 150, 150, 150, - -3295, -3295, -3295, 15129, -3295, 1983, 48616, 48616, 146, -3295, - -3295, -3295, -3295, 1985, -3295, 178, -3295, 69762, -3295, -3295, - -3295, 1950, 1966, 1867, 59582, 2981, 1986, 2474, 2475, 1237, - 1559, -3295, 2157, 37, 69762, -3295, 50974, 69762, 59582, 59582, - 59582, 54537, -3295, -3295, -3295, 1990, 1991, -3295, 47, 2229, - 2222, 59582, 2037, 59582, 2001, -3295, -3295, 59582, 2008, 2489, - 59582, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, 831, -3295, 58085, -3295, 1559, - 1559, 18867, 2385, 59582, 1918, -3295, -3295, -3295, -3295, 69762, - -3295, -3295, 48616, -3295, 48616, -3295, -3295, 50974, -3295, 1115, - -3295, 1115, 2255, 69762, 45892, 1115, 46401, 1115, 2012, -3295, - 48616, 9074, 48616, 2182, -3295, 260, 2334, 811, 811, 811, - 3261, 2368, 249, 2019, 811, 811, 811, 333, 333, 260, - 260, 260, 2334, 440, 980, 52501, 2021, -3295, 48616, 48616, - -3295, -3295, 2022, -3295, -3295, -3295, -3295, 2027, 2036, -3295, - -3295, -3295, -3295, 69762, 186, 1628, 525, 525, 525, 525, - -3295, 59582, 59582, 59582, 48616, 2490, 2364, -3295, -3295, 2549, - 2039, -3295, -3295, 4506, 48616, 59582, -3295, 28459, -3295, 59582, - -3295, 2397, -3295, 2486, -3295, 59582, 848, -3295, -3295, -3295, - 867, 2044, 1857, 58085, 868, 869, -3295, 152, 2168, 2047, - 1556, 1544, 938, 1443, -3295, 56049, -3295, -3295, 2048, 48422, - 21003, -3295, 2429, -3295, -3295, -3295, 48616, 21003, 21003, -3295, - 43732, -3295, -3295, -3295, -3295, -81, -81, -3295, 9493, 1900, - 2051, 2053, 59582, 11411, 48536, -3295, 40677, -3295, 73, 9629, - 48616, -3295, 1831, -3295, -3295, 6176, 21003, 3078, 5169, 21003, - 2055, 21003, 2405, -3295, -3295, 2052, -3295, -3295, 58085, 21003, - 2062, 3889, 26343, 26343, 4426, -3295, 4459, 21003, 11411, -3295, - 44397, 2566, 2066, 1963, 19401, -3295, 2289, 2060, -3295, 2177, - 150, 2177, 2069, -3295, -3295, -3295, 69762, -3295, 2345, 2072, - -3295, 21003, 2234, 69762, 557, 2266, 4506, 873, -3295, 565, - 42204, 1965, 21003, 250, -3295, -3295, 2074, -3295, 1957, -3295, - -3295, -3295, 2308, -3295, -3295, -3295, 59582, -3295, 2079, -3295, - 39150, 2426, 11945, -3295, 39150, 59582, -3295, -3295, 69762, 59582, - 9796, 2456, -3295, 69762, 69762, 69762, -3295, 69762, 2082, 2088, - 1024, 2091, 814, -3295, 2406, -3295, -3295, 1024, 2442, 279, - 2008, 290, 3000, 473, -3295, -3295, -3295, 2173, 59582, -3295, - 69762, -3295, -3295, -3295, -3295, -3295, 51483, -3295, -3295, 43222, - 50974, -3295, 50974, 21003, 21003, 59582, 59582, 59582, 59582, 69762, - 59582, 59582, 59582, 59582, 59582, 1514, -3295, -3295, 21003, 21003, - -3295, 2092, 2093, 2096, 1963, -3295, 206, -3295, 2097, -3295, - -3295, 21003, -3295, -85, -3295, -3295, 178, 2098, 2100, -3295, - 54028, 2223, 59088, 1832, -3295, 1796, 1966, 1044, 69253, 1867, - 21003, -3295, 874, 884, 2981, 2101, 2591, -3295, -3295, -3295, - 826, 54028, -3295, -3295, -3295, 2546, -3295, 812, 259, -3295, - 2593, 1406, -3295, 1237, -3295, 2223, 1559, -3295, 32539, 1821, - -3295, -3295, 2594, -3295, 2595, 2223, 48616, 69762, 2172, -3295, - 424, -3295, -3295, -3295, 69762, 2105, -3295, 2105, -3295, -3295, - 2105, -3295, -3295, -3295, -3295, 26343, 2464, 2112, 58085, -3295, - -3295, 59582, -3295, -3295, -3295, 894, 2113, 2177, 59582, 59582, - 59582, 59582, -3295, -3295, -3295, 19935, 21003, 2152, 21003, -3295, - -3295, 2114, 14081, 2443, -3295, 27945, -3295, -3295, 2116, 39659, - 69762, -3295, -3295, -3295, -3295, 2168, -3295, -3295, 69762, -3295, - -3295, 2125, 2126, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - -3295, -3295, 21003, 48616, -3295, 48616, -3295, -3295, -3295, -3295, - -3295, 59582, -3295, -3295, 7617, -3295, 2124, 2129, 69762, 59582, - 128, -3295, 21003, -3295, 2059, -3295, 452, 21003, 21003, 2417, - -3295, 10249, 21003, 58085, 902, 2417, 293, 21003, 5189, 5219, - 21003, 21003, 5372, 9902, -3295, 23673, 14595, -3295, 2136, 21003, - 10043, 42713, -3295, 34057, 2364, 2138, 2364, 1115, -3295, 2139, - 2137, -3295, -3295, 1975, 48616, 21003, -3295, -3295, -3295, -3295, - 2188, -5, 36093, 2378, -3295, 2191, 2161, 69762, -3295, 2234, - 48616, -3295, -3295, 43732, -3295, -3295, -3295, -3295, -3295, 2614, - 1917, 2150, 2159, -3295, 1370, -3295, -3295, -3295, 69762, 2160, - -3295, 2180, 1024, -3295, 69762, 2193, -3295, 269, 2483, 157, - -3295, 21003, -3295, 2577, 2658, 2406, 2174, 69762, 59582, 26343, - -3295, 285, 272, -3295, 2471, 59582, 2193, 2616, -3295, -3295, - -3295, 814, -3295, 2513, 2423, -3295, 252, -3295, 21003, 814, - 2425, 153, 69762, -3295, -3295, 2770, -3295, 58085, 424, 424, - -3295, 1623, 2181, 2186, 2187, 2190, 2194, 2197, 2199, 2201, - 2206, 2208, 2210, 2213, 2214, 2215, 2217, 2220, 2225, 2227, - 2230, 2240, 1639, 2243, -3295, 2244, 2074, 2245, 2246, 2247, - 2248, 2251, 75361, 2254, 2258, 2259, 2260, 1640, 2263, 2267, - 444, 562, -3295, -3295, -3295, -3295, -3295, -3295, 1306, 2268, - -3295, 2195, -3295, 2189, 904, -3295, -3295, 2281, -3295, 2292, - -3295, -3295, -3295, -3295, -3295, -3295, 2207, 2231, -3295, -3295, - -3295, 150, 2235, 2271, 69762, 10346, 1350, 121, 50974, 69762, - 2274, 2037, -3295, 2701, 771, 2466, 2221, 2278, -3295, 48616, - -3295, 50974, 1832, -3295, 54028, 3636, 664, 2222, 58085, -3295, - 737, 2037, -3295, 2644, 59088, -3295, 2276, 2264, 1832, 2309, - -3295, 1796, -3295, -3295, 21003, 21003, 2380, 21003, 160, -3295, - 2514, 69762, 2284, -3295, 2105, 4604, 26343, 58085, 952, 960, - -3295, 2804, 2455, 2364, -3295, -3295, -3295, -3295, -3295, 2290, - 439, 2291, 10877, 2294, -3295, -3295, -3295, -3295, -3295, -3295, - 48616, 48616, 69762, 2479, 48616, -3295, -3295, 2296, 2293, 41186, - 2767, 2300, -3295, -3295, 2629, -3295, 31536, -3295, 1857, 2310, - 1857, 58085, 1857, -3295, -3295, 48616, 1900, 21003, -3295, -3295, - -3295, 2304, 2303, 69762, 44667, 2645, -3295, 2417, 2417, 10249, - 961, -3295, 2417, 21003, 21003, 2417, 2417, 21003, -3295, 20469, - 231, -3295, 969, -3295, 44249, -3295, 76349, -3295, -3295, 2152, - 1115, 2152, -3295, -3295, 69762, 2311, 2313, -3295, -3295, -3295, - 2366, -3295, -3295, 990, 2759, 2234, 191, -3295, -3295, 2191, - 2234, 21003, -3295, -3295, 2323, 39150, -3295, -3295, -3295, -3295, - 39150, 1024, -3295, 2501, 2193, 2330, -3295, -3295, -3295, -3295, - -3295, -3295, 44267, -3295, 79, 21003, -3295, 1001, 3261, -3295, - -3295, -3295, -3295, 2193, 1237, -3295, 59582, 2823, 2712, -3295, - -3295, 48616, -3295, -3295, 2168, 2168, -3295, -3295, 2486, -3295, - -3295, 2340, 1306, 401, 43222, -3295, -3295, 59582, 59582, -3295, - -3295, 2342, -3295, -3295, -3295, -3295, -3295, -3295, -85, 2742, - 996, 1015, 826, -3295, 2223, 59582, 2721, 54028, 50974, -3295, - 2835, 2353, 59582, 2037, 1178, 1178, -3295, 2510, -3295, 2517, - -3295, -3295, -3295, -3295, 1115, 2848, 301, -3295, 48616, 48616, - 1414, 59582, -3295, -3295, 35584, 4604, 1023, -3295, -3295, 2367, - 2371, -3295, 2152, 21003, 2372, 21003, -3295, 24207, 2860, 2373, - -3295, 21003, 2436, 28973, -3295, 21003, -3295, 59582, 64672, 2376, - 64672, -3295, -3295, -3295, -3295, 59582, -3295, -3295, -3295, 21003, - -3295, 2417, 2417, 2417, 21003, 21003, -3295, -3295, -3295, -3295, - 2592, 2479, -3295, 2479, -3295, -3295, 21003, 2223, 565, 3646, - 69762, 12, -3295, 2869, 2657, -3295, -3295, 48616, -3295, -3295, - -3295, 59582, -3295, 50974, -3295, 1024, 8, 2384, 21003, 44302, - 2628, -3295, -3295, 2662, -3295, 2723, -3295, 2450, 630, 2468, - -3295, -3295, -3295, -3295, 1350, 1115, -3295, 1832, 2222, 2309, - 2392, 59582, 1029, 2223, 826, 812, -3295, -3295, -3295, -3295, - -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, -3295, - 2223, 2846, 2624, 2850, -3295, 2172, 21003, 110, -3295, 1033, - 2842, -3295, -3295, 2915, 2479, 2399, 24207, 2401, -3295, 2403, - 69762, 48616, 2555, -3295, -3295, 2413, -3295, -3295, 21003, -3295, - -3295, 44878, 2408, 2416, 2874, 1963, 2436, 2436, -3295, -5, - -3295, -3295, 2852, 35584, 2810, 21003, 2511, 2889, 1237, 1024, - 2433, 1045, -3295, -3295, -3295, -3295, -3295, 2981, -3295, 44320, - 2673, 601, 2659, 2384, 21003, -3295, 2502, -3295, -3295, -3295, - 2914, -3295, -3295, 54028, 2428, -3295, 2309, 2222, 2037, 2309, - 2660, -3295, 2668, 2439, 44355, 69762, 69762, 1832, 35584, 69762, - 2448, 2436, -3295, 2449, -3295, -3295, -3295, 30515, -3295, 2457, - -3295, -3295, -3295, 21003, 169, -3295, -3295, 2496, 59582, 1075, - 82, 48616, 276, 434, 2869, 2662, 43222, -3295, 50974, 1028, - 8, 2765, -3295, -3295, -3295, -3295, 241, 2690, -3295, 2692, - -3295, 48616, -3295, 2223, 54028, -3295, -3295, -3295, -3295, -3295, - -3295, 35584, 2842, -3295, 351, -3295, 1628, -3295, 351, -3295, - -3295, -3295, -3295, -3295, 1566, 24741, 24741, 24741, 2461, 2223, - -3295, 1628, -3295, 2596, -3295, 2713, 21003, 129, 246, -3295, - -3295, -3295, 2557, 2659, -3295, -3295, -3295, -3295, -3295, 533, - 533, 2872, -3295, 2533, -3295, 2309, 1103, 69762, 1957, -3295, - 1957, 25809, 2626, 211, 47469, 2853, -3295, 2853, 2853, -3295, - -3295, -3295, 42204, -3295, -3295, 48616, 2525, 69762, 2488, 2531, - 41695, -3295, 276, -3295, -3295, 2984, -3295, 268, -3295, -3295, - -3295, 1832, 351, -3295, -3295, 2977, -3295, -3295, -3295, -3295, - -3295, 951, -3295, -3295, -3295, 1628, -3295, 1110, -3295, -3295, - 2491, -3295, -3295, -3295, 1024, -3295, -3295, -3295, 1628, 1957, - 25275, 2647, -3295, 2715, -3295, -3295, -3295, 21003, -3295, -3295, - -3295, -3295, -3295, 2498, -3295 + 6857, 34, 170, -3336, -3336, 257, 34, 53203, 69955, 524, + 34, 126, 3470, 55733, -3336, -3336, 50149, 10226, 34, 59775, + 77525, 412, 428, 33917, 790, 60284, -3336, -3336, -3336, 69955, + 59775, 60793, 34, 392, 70464, -3336, 34, 36973, 56242, 482, + -3336, 59775, 61, 404, 61302, 59775, 3101, 959, 387, -3336, + -3336, -3336, -3336, -3336, 184, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, 157, -3336, 707, 174, 33917, 33917, 92, + 529, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, 629, -3336, -3336, 905, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, 36463, -3336, -3336, -3336, -3336, -3336, -3336, + 70973, 61811, 59775, 62320, 56751, 62829, -3336, 804, 769, 1145, + 836, 187, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, 190, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, 672, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, 202, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, 638, -3336, 679, -3336, 206, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, 1935, -3336, -3336, 1105, + 2799, 59775, 742, 883, 874, -3336, 63338, -3336, 865, -3336, + -3336, 871, 716, 1087, -3336, -3336, 57260, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, 50658, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, 1074, -3336, -3336, 901, -3336, + 243, -3336, -3336, 911, 897, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, 1005, -3336, -3336, -3336, 1016, 71482, + 63847, 64356, -3336, 895, 863, 934, 6755, 77543, 32897, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, 629, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, 60284, 69955, 920, 929, 1268, 938, 34935, + 956, 37483, 989, 1046, 1269, 1055, 1067, 1076, 1085, 404, + 33407, 1095, 638, 1458, 64865, 64865, 10, 34426, 3008, -3336, + 64865, 65374, -3336, 1124, -3336, 1145, -3336, -3336, -3336, -3336, + -45, 1093, -3336, 65883, 65883, 65883, 1129, 1443, 65883, -3336, + -3336, -3336, 1163, -3336, -3336, 1410, 20863, 20863, 71991, 71991, + 1145, 71991, 1221, 71991, -3336, -3336, 288, 836, -3336, 638, + -3336, -3336, 92, -3336, -3336, 56242, -3336, -3336, 309, 1561, + 20863, 59775, 1204, -3336, 1212, 1204, 1213, 1223, 1225, -3336, + 6857, 1576, 1465, 1553, 57769, 395, 395, 1718, 395, 968, + 1064, 3220, 4836, -3336, 1654, -3336, 1258, -3336, 59775, 60284, + 1360, 1618, 1293, 1602, -3336, -3336, 1667, 1477, 1692, 925, + 1510, 1722, 2191, 1732, 928, 1737, 1172, 1739, 1770, 1846, + 58, -3336, 20863, 51167, 638, -3336, 12339, 20863, -3336, -3336, + -3336, 1462, -3336, -3336, -3336, -3336, -3336, 59775, 69955, 1365, + 1369, -3336, -3336, -3336, -3336, 992, 1620, -3336, 72500, -3336, + -3336, 1418, 66392, 66901, 67410, 67919, 68428, 1812, -3336, -3336, + 1751, -3336, -3336, -3336, 1407, -3336, -3336, -3336, 223, 73009, + 1754, 1382, 120, -3336, 1755, 245, -3336, 1759, 1619, 14989, + -3336, 1558, -3336, -3336, -3336, 404, -3336, 328, -3336, -3336, + 46559, -3336, -3336, 77543, 1481, 1397, -3336, 20863, 20863, 1401, + 8683, 64865, 65374, 20863, 59775, -3336, 20863, 26203, 1404, 20863, + 20863, 12873, 20863, 30887, 64865, 3008, 1405, -3336, 799, -3336, + 59775, 1408, -3336, 1504, 1504, 392, 33917, 1719, 33407, 1504, + 1888, 1504, -3336, 1122, 1716, 1639, -3336, 33917, 1639, 1693, + 1417, 1723, 1639, -3336, 285, 1724, 1888, 37992, 1421, -3336, + 1504, 1650, -3336, -3336, 20863, 14989, 58278, 1912, -3336, -3336, + -3336, -3336, 1715, -3336, 69955, 1430, -3336, -3336, -3336, -3336, + -3336, -3336, 802, 1956, 186, 1957, 20863, 186, 186, 1435, + 215, 215, -3336, 1634, 1441, -3336, 219, 1442, 1445, 1969, + 1970, 196, 59775, 180, 1089, 186, 20863, -3336, 215, 1450, + 1975, 1453, 2002, 228, 230, -3336, 1483, 225, 20863, 20863, + 20863, 353, 20863, 11271, -3336, 51167, 2004, 59775, 207, -3336, + 638, 1487, 1145, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + 1489, -3336, 201, 6224, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, 1529, -3336, -3336, -3336, -3336, 1720, 20863, -3336, + -3336, 1490, 1719, -3336, 227, -3336, -3336, 1719, -3336, -3336, + -3336, -3336, -3336, 246, -3336, 1920, 20863, 20863, -3336, 638, + 73518, -3336, -3336, -3336, -3336, -3336, -3336, -3336, 684, -3336, + 629, 671, 48185, 1494, 1502, 1204, 59775, 59775, 1565, -3336, + -3336, -3336, -3336, 56242, 606, 1813, 56242, 144, 1638, -3336, + -3336, 92, 92, 16057, 1041, 239, 1036, 16591, 21397, 1865, + 1744, 253, 644, 1868, -3336, 1748, 1980, 26203, 20863, 20863, + 968, 1064, 20863, 1212, 104, -3336, -3336, 59775, -3336, 1803, + 69955, 1601, 59775, 53712, 768, 893, 1517, 1606, 54, 841, + 1953, -3336, 1516, -3336, 1611, 59775, 76048, 248, -3336, 1993, + 248, 248, 682, 1994, 1617, 280, 1787, 1084, -35, 1516, + 2821, -3336, 56242, 204, 1329, 1516, 59775, 1621, 1378, 1516, + 1770, 1145, 69955, 1536, -3336, -3336, 44180, 2043, -3336, -3336, + -3336, 185, 14989, -3336, 1259, 1340, 1379, 1403, -3336, 378, + 226, 1414, 1508, 14989, 1534, 1557, 189, 1595, 1614, 1713, + 1725, 1731, 1733, 1735, 1747, 166, 1749, 1758, 1760, 1769, + 1777, 1794, -3336, 1800, 199, 1802, 232, 1483, 14989, 1806, + -3336, 176, 48185, 35, -3336, -3336, 1811, 203, -3336, 48358, + -3336, 1850, 1636, 1637, 69955, 1589, 59775, 1694, 868, 1929, + 1983, 1810, -3336, 1892, 59775, 1815, 2821, 1816, 1569, 2057, + 1819, 2059, 1823, 1369, 1824, 1578, -3336, 74027, 51167, -3336, + -3336, -3336, -3336, -3336, 1958, 1933, 69955, 51167, 1585, -3336, + -3336, 69955, -3336, 59775, 59775, -3336, 59775, 69955, -3336, 694, + 48185, 2103, 706, 77543, 52185, -3336, -3336, -3336, -3336, 1099, + 1235, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + 1145, 51167, -3336, 2415, 47118, 1588, 20863, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, 1590, 1948, + -3336, -3336, 4826, 1596, 47136, 1598, 26203, 26203, 638, 2788, + -3336, -3336, 26203, 1599, 52694, 6312, 1592, 1604, 47213, 17125, + 20863, 17125, 17125, 47470, -3336, 1605, 47659, 64865, 1608, 59775, + 30375, -3336, -3336, -3336, 20863, 20863, 3008, 58772, 1651, 1610, + -3336, 1609, 1504, -3336, 33917, -3336, 33917, -3336, 1915, 33917, + -3336, -3336, 3927, -3336, 33917, 1916, 20863, 33917, -3336, 33917, + 1858, 1859, 1622, 33917, 1504, 59775, 1623, 59775, -3336, -3336, + 48185, -3336, 1616, 810, 1624, -3336, -3336, -3336, -3336, -3336, + -3336, 1672, -3336, -3336, 1672, 1672, -3336, -3336, -3336, -3336, + 1628, 1628, 1630, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, 1631, 1089, -3336, 1672, + -3336, 1628, -3336, -3336, -3336, -3336, -3336, -3336, -3336, 76542, + -3336, -3336, -3336, -3336, 347, 388, -3336, 1632, -3336, -3336, + -3336, 1633, -3336, 127, 2112, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, 10246, 826, 1628, -3336, -3336, 4056, + -3336, -3336, 20863, 20863, -3336, -3336, 1640, 48185, 1679, -3336, + -3336, 20863, 20863, -3336, -3336, -3336, -3336, 2157, -3336, 237, + 20863, 1672, 1672, -3336, 8366, -3336, 43592, 17659, 1738, 1742, + 2157, -3336, 2157, -3336, 20863, 8366, 2158, 2158, 1642, 38501, + -3336, 1814, 47740, -3336, 1644, 2242, 7222, 1641, -3336, -3336, + 2163, -3336, 1653, 1649, 20863, 45032, 163, 638, 638, 20863, + -3336, 2157, 20863, 44403, 44403, -3336, 231, 58278, 20863, 20863, + 20863, 20863, 20863, 20863, 20863, 20863, 49131, 1752, 192, 69955, + 20863, 20863, 29861, 918, -3336, 20863, 1902, -3336, 1663, 20863, + 1762, 390, 20863, 20863, 20863, 20863, 20863, 20863, 20863, 20863, + 20863, -3336, -3336, 29347, 264, 724, 2012, 2033, 453, 312, + 20863, 2025, 12339, -3336, 2025, -3336, -3336, -3336, -3336, -3336, + 229, -3336, -3336, 1616, 1616, 69955, -3336, 59775, 309, 55224, + 20863, -3336, -3336, 1671, 1675, 1977, 2166, 1741, -3336, -3336, + 59775, 1750, -3336, 42064, 1995, -3336, 396, 1684, -3336, 47065, + 1949, 1995, 92, -3336, -3336, 26737, 1825, 1992, 1926, -3336, + -3336, 1906, 1907, -3336, 1695, 48432, 21931, 21931, -3336, 1456, + 48185, 1460, -3336, -3336, -3336, -3336, -3336, -3336, 56, -3336, + 59775, 647, 39010, -3336, 1697, 339, -3336, 3577, 2050, 2013, + 1865, 644, 1705, -3336, 60284, 60284, -3336, -3336, -3336, 1883, + 69955, 1392, 1717, 74536, 59775, 2014, 1967, 2019, -22, 58278, + -3336, 1721, -3336, -3336, -3336, 59775, 69955, 68937, 75045, 51676, + 59775, 2189, 2190, 49640, -3336, -3336, 2195, 2197, -3336, -3336, + 59775, 770, 59775, 6256, -3336, -3336, -3336, -3336, 248, -3336, + -3336, -3336, -3336, -3336, 69955, 59775, -3336, -3336, 248, 69955, + 59775, 248, -3336, 1422, 59775, 59775, 69955, 59775, 1512, 59775, + 59775, 1145, 1846, -3336, 51167, -3336, -3336, 22465, 82, 82, + 1962, 1971, 1982, 1743, 13407, 176, -3336, 20863, 20863, 188, + 289, 69955, 1924, -3336, -3336, 852, 1981, 155, -3336, 69955, + 1793, 59775, 59775, 59775, 59775, 59775, 59775, 890, -3336, -3336, + -3336, -3336, -3336, 2123, 2275, 1753, 1757, 2125, -3336, 2821, + 2126, 54221, -3336, 2307, 2132, 59281, 2135, 1801, 2136, 31905, + -3336, -3336, 1761, -3336, -3336, 1763, 2253, 2016, -3336, -3336, + 2005, -3336, 69955, 2294, -3336, 120, -3336, 51167, -3336, 245, + -3336, 2006, 238, -3336, 14989, 20863, -3336, -3336, -3336, -3336, + -3336, -3336, 1397, 20863, -3336, 857, -3336, -3336, 2261, 1145, + 2261, 797, -3336, -3336, 2261, -3336, 2243, 2261, -3336, 58278, + -3336, 7479, -3336, 20863, 20863, -3336, 20863, 2133, -3336, 2299, + 2299, 58278, 26203, 26203, 26203, 26203, 26203, 26203, 676, 1450, + 26203, 26203, 26203, 26203, 26203, 26203, 26203, 26203, 26203, 27271, + 322, -3336, -3336, 881, 2270, 20863, 20863, 2144, 2133, 20863, + -3336, 58278, 1786, -3336, 1789, 1790, 20863, -3336, 58278, -3336, + 59775, 1795, -3336, -3336, -3336, 6, 1788, 1798, -3336, -3336, + 1719, -3336, 1057, 1072, 59775, 3335, 3894, 4033, -3336, -3336, + 20863, 2139, -3336, 399, -3336, 3927, 3927, 33917, -3336, 20863, + 1805, -3336, -3336, 33917, 2159, -3336, 3927, -3336, -3336, 39519, + 3927, -3336, 58278, 882, -3336, 59775, 58278, 889, 20863, -3336, + 14989, 2327, 58278, 130, 2301, 69955, 69955, 1808, 2336, 1817, + 1822, 1817, 2157, 1909, -3336, 1918, 1919, 1921, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, 58278, -3336, + -3336, 255, -3336, -3336, -3336, -3336, -3336, -3336, 1831, 1836, + 20863, 20863, 131, -3336, 7528, 1835, 1842, 20863, 47787, -3336, + 1840, -3336, 1848, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + 1853, -3336, 1863, -3336, 1867, 1876, 1877, 1873, 1874, 7831, + 20863, 59775, -3336, 1878, 22999, 2038, 59775, -3336, -3336, 20863, + 20863, 59775, -3336, 48185, 2259, -3336, 1884, 1885, 7883, -3336, + -3336, -3336, 261, 418, 48323, 312, 5228, 5228, 5228, 8366, + -3336, -3336, -3336, 1905, -3336, 26203, 26203, -3336, 5100, 3059, + 11271, -3336, -3336, -3336, -3336, 2244, -3336, 801, -3336, 1889, + -3336, -3336, 4451, -3336, 43592, 48629, 20863, 197, -3336, 20863, + 29861, 20863, 1984, 5228, 5228, 5228, 417, 417, 261, 261, + 261, 418, 312, -3336, -3336, -3336, 1893, 20863, 51167, -3336, + 1895, 1897, 2269, 1453, 20863, -3336, -3336, 33917, 1651, 35, + 1651, 2157, 44403, -3336, 1212, -3336, 1212, -3336, 48185, 59775, + -3336, 1899, 798, 33917, 1941, 2388, 2370, 33917, 69955, -3336, + -3336, 1901, 2025, 1917, -3336, -3336, 1923, 20863, 2008, 1923, + -3336, 1995, 36, 2143, 1300, 1300, 1456, 2155, -3336, -3336, + 1989, -3336, -3336, -3336, 20863, 15523, 1467, -3336, 1469, -3336, + -3336, -3336, -3336, -3336, 1927, -3336, 2209, -3336, 59775, -3336, + -3336, 26203, 2401, 20863, 40028, 2403, 2196, -3336, -3336, -3336, + 1987, 1987, -3336, -3336, 2030, -3336, 2035, 1516, 20863, 2193, + -3336, 146, 1951, 2322, -20, 2272, 69955, -3336, -3336, -3336, + 355, 775, 51167, 1721, -3336, -3336, 210, 2326, 238, 2328, + 238, 51167, 51167, 51167, 907, -3336, -3336, -3336, 1145, -3336, + -3336, -3336, 1968, -59, 909, -3336, 1961, 1964, -3336, -3336, + -3336, 2044, 1511, 1516, 2821, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, 269, 1531, 1516, 2046, -3336, 2058, -3336, 2060, + 1532, 1516, -3336, -3336, 1846, 1536, 915, 18193, 48185, 235, + 176, 176, 176, -3336, -3336, -3336, 14989, -3336, 1973, 48185, + 48185, 153, -3336, -3336, -3336, -3336, 1978, -3336, 173, -3336, + 69955, -3336, -3336, -3336, 1924, 1983, 1892, 59775, 2821, 1985, + 2456, 2462, 1369, 1578, -3336, 2148, 714, 69955, -3336, 51167, + 69955, 59775, 59775, 59775, 54730, -3336, -3336, -3336, 1986, 1988, + -3336, 40, 59775, 2022, 59775, 1991, -3336, -3336, 59775, 1998, + 2473, 59775, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, 921, -3336, 58278, -3336, + 1578, 1578, 18727, 2362, 59775, 1933, -3336, -3336, -3336, -3336, + 69955, -3336, -3336, 48185, -3336, 48185, -3336, -3336, 51167, -3336, + 1145, -3336, 1145, 2251, 69955, 45541, 1145, 46050, 1145, 2009, + -3336, 48185, 8252, 48185, 2144, -3336, 211, 2299, 1278, 1278, + 1278, 5494, 2366, 244, 2018, 1278, 1278, 1278, 346, 346, + 211, 211, 211, 2299, 322, 1124, 52694, 2020, -3336, 48185, + 48185, -3336, -3336, 2015, -3336, -3336, -3336, -3336, 2023, 2026, + -3336, -3336, -3336, -3336, 69955, 177, 1651, 482, 482, 482, + 482, -3336, 59775, 59775, 59775, 48185, 2481, 2354, -3336, -3336, + 2533, 2029, -3336, -3336, 3927, 48185, 59775, -3336, 28319, -3336, + 59775, -3336, 2382, -3336, 2479, -3336, 59775, 949, -3336, -3336, + -3336, 950, 2037, 2039, 1817, 58278, 954, 964, 2157, -3336, + 209, 2157, 2032, 1581, 967, 845, 1468, -3336, 56242, -3336, + -3336, 2042, 47988, 20863, -3336, 2420, -3336, -3336, -3336, 48185, + 20863, 20863, -3336, 43592, -3336, -3336, -3336, -3336, 561, 561, + -3336, 8441, 1878, 2034, 2045, 59775, 11271, 48057, -3336, 40537, + -3336, 64, 8796, 48185, -3336, 1814, -3336, -3336, 44403, 20863, + 3624, 5174, 20863, 2047, 20863, 2393, -3336, -3336, 2049, -3336, + -3336, 58278, 20863, 2051, 4579, 26203, 26203, 4654, -3336, 7194, + 20863, 11271, -3336, 44215, 2553, 2054, 1962, 19261, -3336, 2267, + 2055, -3336, 2139, 176, 2139, 2061, -3336, -3336, -3336, 69955, + -3336, 2321, 2064, -3336, 20863, 2211, 69955, 168, 1809, 3927, + 969, -3336, 638, 42064, 1941, 20863, 297, -3336, -3336, 2065, + -3336, 1923, -3336, -3336, -3336, 2283, -3336, -3336, -3336, 59775, + -3336, 2066, -3336, 39010, 2400, 11805, -3336, 39010, 59775, -3336, + -3336, 69955, 59775, 9135, 2435, -3336, 69955, 69955, 69955, -3336, + 69955, 2062, 2067, 691, 2069, 1042, -3336, 1974, -3336, -3336, + 691, 2421, 268, 1998, 280, 2598, 123, -3336, -3336, -3336, + 2149, 59775, -3336, 69955, -3336, -3336, -3336, -3336, -3336, 51676, + -3336, -3336, 20863, 20863, 51167, -3336, 49640, 20863, 20863, 59775, + 59775, 59775, 59775, 69955, 59775, 59775, 59775, 59775, 59775, 1536, + -3336, -3336, 20863, 20863, -3336, 2074, 2076, 2077, 1962, -3336, + 159, -3336, 2080, -3336, -3336, 20863, -3336, -35, -3336, -3336, + 173, 2084, 2086, -3336, 54221, 2799, 59281, 1801, -3336, 1763, + 1983, 884, 69446, 1892, 20863, -3336, 976, 1008, 2821, 2087, + 2575, -3336, -3336, -3336, -3336, 54221, 2557, 2558, 31, 2329, + -3336, 2324, 895, 293, -3336, 2580, 1682, -3336, 1369, -3336, + 2799, 1578, -3336, 32399, 1841, -3336, -3336, 2583, -3336, 2584, + 2799, 48185, 69955, 2164, -3336, 238, -3336, -3336, -3336, 69955, + 2100, -3336, 2100, -3336, -3336, 2100, -3336, -3336, -3336, -3336, + 26203, 2461, 2108, 58278, -3336, -3336, 59775, -3336, -3336, -3336, + 1014, 2113, 2139, 59775, 59775, 59775, 59775, -3336, -3336, -3336, + 19795, 20863, 2154, 20863, -3336, -3336, 2115, 13941, 2436, -3336, + 27805, -3336, -3336, 2116, 39519, 69955, -3336, -3336, -3336, -3336, + 2157, 2157, -3336, -3336, 69955, -3336, 2119, -3336, 2120, 2121, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, 20863, + 48185, -3336, 48185, -3336, -3336, -3336, -3336, -3336, 59775, -3336, + -3336, 6766, -3336, 2122, 2124, 69955, 59775, 128, -3336, 20863, + -3336, 2038, -3336, 431, 20863, 20863, 5100, -3336, 9276, 20863, + 58278, 1023, 5100, 377, 20863, 5248, 5273, 20863, 20863, 8075, + 9448, -3336, 23533, 14455, -3336, 2128, 20863, 9765, 42573, -3336, + 33917, 2354, 2129, 2354, 1145, -3336, 2131, 2134, -3336, -3336, + 4056, 48185, 20863, -3336, -3336, -3336, -3336, 2178, 429, 35953, + 2368, -3336, 2184, 2147, 69955, -3336, 2211, 48185, -3336, -3336, + 43592, -3336, -3336, -3336, -3336, -3336, 2611, 2097, 2152, 2153, + -3336, 1386, -3336, -3336, -3336, 69955, 2160, -3336, 2165, 691, + -3336, 69955, 2182, -3336, 303, 2466, 121, -3336, 20863, -3336, + 2559, 2645, 1974, 2169, 69955, 59775, 26203, -3336, 313, 291, + -3336, 2459, 59775, 2182, 2603, -3336, -3336, -3336, 1042, -3336, + 2505, 2416, -3336, 248, -3336, 20863, 1042, 2417, 252, 69955, + -3336, -3336, 3141, -3336, 58278, 238, 238, -3336, 48185, 48185, + 2186, -3336, 2181, 1024, -3336, -3336, 2273, -3336, 2274, -3336, + -3336, -3336, -3336, -3336, -3336, 2185, 2188, -3336, -3336, -3336, + 176, 2192, 2194, 69955, 9816, 1397, 156, 51167, 69955, 2198, + 2022, -3336, 2676, 955, 2440, 2200, 2201, -3336, 48185, -3336, + 51167, 1801, -3336, 54221, 2750, 308, 40, 58278, -3336, 2204, + 2205, -3336, -3336, -3336, 2635, -3336, 2022, -3336, 2616, 59281, + -3336, 2207, 2208, 1801, 2235, -3336, 1763, -3336, -3336, 20863, + 20863, 2310, 20863, 150, -3336, 2431, 69955, 2215, -3336, 2100, + 6024, 26203, 58278, 1034, 1050, -3336, 2730, 2384, 2354, -3336, + -3336, -3336, -3336, -3336, 2218, 415, 2220, 10737, 2217, -3336, + -3336, -3336, -3336, -3336, -3336, 48185, 48185, 69955, 2408, 48185, + -3336, -3336, 2219, 2223, 41046, 2693, 2225, -3336, -3336, 2554, + -3336, 31396, -3336, 1817, 2229, 2230, 1817, 58278, 1817, -3336, + -3336, -3336, 48185, 1878, 20863, -3336, -3336, -3336, 2227, 2232, + 69955, 44257, 2568, -3336, 5100, 5100, 9276, 1060, -3336, 5100, + 20863, 20863, 5100, 5100, 20863, -3336, 20329, 249, -3336, 1068, + -3336, 9901, -3336, 77036, -3336, -3336, 2154, 1145, 2154, -3336, + -3336, 69955, 2234, 2233, -3336, -3336, -3336, 2292, -3336, -3336, + 1070, 2674, 2211, 610, -3336, -3336, 2184, 2211, 20863, -3336, + -3336, 2241, 39010, -3336, -3336, -3336, -3336, 39010, 691, -3336, + 2422, 2182, 2245, -3336, -3336, -3336, -3336, -3336, -3336, 10171, + -3336, 66, 20863, -3336, 1127, 5494, -3336, -3336, -3336, -3336, + 2182, 1369, -3336, 59775, 2733, 2623, -3336, -3336, 48185, -3336, + -3336, 2157, 2157, -3336, -3336, 2479, -3336, -3336, 43082, -3336, + -3336, 59775, 59775, -3336, -3336, 2249, -3336, -3336, -3336, -3336, + -3336, -3336, -35, 2654, 1100, 1107, -3336, -3336, 2799, 59775, + 2627, 54221, 51167, -3336, 2742, 2255, 59775, 2022, 1710, 1710, + 2324, 20863, 20863, 298, -3336, -3336, -3336, -3336, 1145, 2747, + 319, -3336, 48185, 48185, 1441, 59775, -3336, -3336, 35444, 6024, + 1115, -3336, -3336, 2263, 2266, -3336, 2154, 20863, 2279, 20863, + -3336, 24067, 2754, 2282, -3336, 20863, 2344, 28833, -3336, 20863, + -3336, 59775, 64865, 2287, 64865, -3336, -3336, -3336, -3336, -3336, + 59775, -3336, -3336, -3336, 20863, -3336, 5100, 5100, 5100, 20863, + 20863, -3336, -3336, -3336, -3336, 2501, 2408, -3336, 2408, -3336, + -3336, 20863, 2799, 638, 2031, 69955, 27, -3336, 2780, 2566, + -3336, -3336, 48185, -3336, -3336, -3336, 59775, -3336, 51167, -3336, + 691, 407, 2295, 20863, 44109, 2535, -3336, -3336, 2570, -3336, + 2632, -3336, 2359, 1624, 2297, 2298, 2303, 2304, 2311, 2312, + 2315, 2316, 2317, 2318, 2319, 2325, 2330, 2335, 2337, 2338, + 2342, 2343, 2345, 2347, 1631, 2349, -3336, 2350, 2065, 2351, + 2353, 2355, 2356, 2357, 75554, 2358, 2360, 2365, 2367, 1632, + 2369, 2372, 1099, 1235, -3336, -3336, -3336, -3336, -3336, -3336, + 1382, 2376, -3336, -3336, -3336, -3336, 1397, 1145, -3336, 1801, + 40, 2235, 2323, 59775, 1120, 2799, -3336, 895, -3336, -3336, + -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, -3336, + 2302, 2363, 2465, -3336, 2477, -3336, 2799, 2781, 2560, 2784, + -3336, 2164, 20863, 266, -3336, 1134, 2793, -3336, -3336, 2875, + 2408, 2371, 24067, 2378, -3336, 2361, 69955, 48185, 2534, -3336, + -3336, 2381, -3336, -3336, 20863, -3336, -3336, 44527, 2385, 2390, + 2858, 1962, 2344, 2344, -3336, 429, -3336, -3336, 2825, 35444, + 2787, 20863, 2486, 2865, 1369, 691, 2409, 1135, -3336, -3336, + -3336, -3336, -3336, 2821, -3336, 44127, 2649, 171, 2634, 2295, + 20863, -3336, 1382, 567, -3336, -3336, 2892, 2324, -3336, 54221, + 2406, -3336, 2235, 40, 2022, -3336, -3336, -3336, -3336, 2235, + 2637, -3336, 2638, 2410, 44162, 69955, 69955, 1801, 35444, 69955, + 2411, 2344, -3336, 2413, -3336, -3336, -3336, 30375, -3336, 2419, + -3336, -3336, -3336, 20863, 697, -3336, -3336, 2467, 59775, 1157, + 106, 48185, 167, 667, 2780, 2570, 43082, -3336, 51167, 1130, + 407, 2738, -3336, -3336, -3336, -3336, 262, 2651, -3336, 2655, + -3336, 48185, 625, 2500, 2799, -3336, 54221, -3336, 2324, -3336, + -3336, -3336, -3336, 35444, 2793, -3336, 396, -3336, 1651, -3336, + 396, -3336, -3336, -3336, -3336, -3336, 1592, 24601, 24601, 24601, + 2427, 2799, -3336, 1651, -3336, 2562, -3336, 2679, 20863, 250, + 283, -3336, -3336, -3336, 2528, 2634, -3336, -3336, -3336, -3336, + -3336, 758, 758, 2843, -3336, 2503, -3336, 2519, -3336, 2235, + -3336, 1175, 69955, 1923, -3336, 1923, 25669, 2597, 220, 47083, + 2824, -3336, 2824, 2824, -3336, -3336, -3336, 42064, -3336, -3336, + 48185, 2502, 69955, 2455, 2506, 41555, -3336, 167, -3336, -3336, + 2954, -3336, 208, -3336, -3336, -3336, -3336, 1801, 396, -3336, + -3336, 2944, -3336, -3336, -3336, -3336, -3336, 699, -3336, -3336, + -3336, 1651, -3336, 1191, -3336, -3336, 2457, -3336, -3336, -3336, + 691, -3336, -3336, -3336, 1651, 1923, 25135, 2610, -3336, 2683, + -3336, -3336, -3336, 20863, -3336, -3336, -3336, -3336, -3336, 2463, + -3336 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -3295, -3295, -3295, 2140, 84, -3295, -3295, 258, -3295, -3295, - 692, -1729, -1733, 1193, -3295, 251, -758, 691, -3295, 87, - 4693, 2849, 4942, 617, -531, -916, -1266, 18, 89, -1171, - 3, -3295, -3295, -1872, -3295, -1556, -451, 320, -3295, -3295, - -595, -2703, -545, -3295, -3200, -3232, -711, -3295, -2677, -3165, - -2165, 100, -2587, -3295, -3295, 106, 17, -2228, -3295, -1768, - 64, -2183, -3295, -144, -2859, 109, 114, 1095, -3295, -2738, - 117, -910, -1248, -972, -1243, -3295, -40, -3295, -3295, 548, - 126, 1319, 2183, -3295, 19, -2283, -3037, -557, -3295, -673, - -3295, -299, -3295, -611, -3295, -901, -619, -660, -2977, -1186, - -3295, 1823, -351, -3295, 736, -3295, -2742, -3295, -3295, 719, - -3295, 1251, 1252, -3295, -3295, -2366, 222, -594, -2789, -2736, - -2297, -914, 313, -602, 286, -2221, -1299, -3295, 753, -3295, - -586, -3295, -923, -1975, 130, -3295, -3295, 1707, -954, -3295, - 132, -580, -3295, -3295, -677, -3295, -3295, -3295, -3295, -3295, - -242, 135, -3295, 592, -3295, -2263, 595, -2217, 1748, -642, - -3295, 233, 7, 10, -3295, -3295, -3295, -3295, -799, 671, - -1916, -3295, -3295, -3295, -3295, 277, 4, 3275, -41, -32, - -3295, -28, -3295, -3295, -3295, 793, -3295, -3295, 2, 51, - 1915, -3295, -3295, -3295, -3295, -1046, -3295, -1893, 566, -3295, - 2070, 2075, -1821, -891, -33, 315, 837, -1734, -2199, -620, - 1312, 1895, 1902, -3295, 543, -2735, -3295, -528, -3295, -721, - -3295, -3295, -3295, 2065, -3295, 828, 1359, -1552, -1550, -3295, - -2327, -3295, -443, -321, -3295, -3295, -3295, -3295, -3295, -2437, - -3063, -599, 1327, -3295, 1908, -3295, -3295, -3295, -3295, 62, - -1599, 3105, 871, -3295, 203, -3295, -3295, -3295, -3295, 212, - -3295, 1060, -133, -3295, -478, -702, -809, 2122, 147, 217, - -1911, -9, -375, 584, -3295, -3295, 586, -2160, -1466, 538, - -237, 1062, -3295, -2373, -1602, -3295, -1527, -1211, -3295, -3295, - -783, 1498, -3295, -3295, -3295, 2882, 2887, -3295, -3295, 3069, - 3471, -3295, -931, 3592, 1076, -1058, 2135, -973, 2141, -941, - -958, -955, 2143, 2145, 2146, 2147, 2149, 2151, 2153, -1581, - 5816, -959, 3798, -2280, -3295, -1447, -1624, -3295, -3295, -3295, - 50, -3295, -1430, 127, -3295, -3295, -3295, -3295, -2924, -3295, - -424, -3295, -420, -3295, -3295, -3295, -1845, -3294, -1884, -3295, - 4395, 981, -3295, -3295, 524, -3295, -3295, -3295, -3295, -1588, - -3295, 7216, 889, -3295, -2115, -3295, -3295, -1005, -874, -473, - -1035, -1256, -2000, -3295, -3295, -3295, -3295, -3295, -3295, -1188, - -1839, -234, 946, -3295, -3295, 1046, -3295, -3295, -147, -1519, - -1823, -2190, -3295, -3295, -3295, 953, 1682, 158, -848, -1680, - -3295, -1586, -3295, -3295, 1004, -2531, -3295, -3295, 510, -2806, - -3295, -3295, 215, -3295, -694, -1158, -2593, 46, 26, -3295, - 1121, -2691, -3295, -3295, -733, -2851, -1150, -951, -3295, 136, - -3295, 173, 138, -1757, -3295, 23, -3295, -372, -3295, -3295, - -2754, -3295, 142, 149, 2386, -3295, 1290, -3295, -3295, -3295, - -3295, -555, -3295, -652, 2198, -3295, -3295, 30, -3295, 1806, - -3295, 165, 394, -3295, 1116, -3295, 689, 170, -3295, 2312, - -444, 171, 1457, -3295, -3295, -3295, 11, -541, 481, -3295, - 1466, -3295, -3295, -662, -1724, -3295, 695, 1339, -2168, 175, - -3295, 447, 15, -3295, -3295, -3295, 76, 176, 24, -3131, - 177, -2845, -1759, -7, -3295, -3295, -3295, -635, -3295, -2694 + -3336, -3336, -3336, 2104, 83, -3336, -3336, 221, -3336, -3336, + 657, -1749, -1752, 1164, -3336, 217, -808, 658, -3336, 88, + 4257, 2924, 4559, 1332, -530, -916, -1296, 4, 89, -1170, + 11, -3336, -3336, -1879, -3336, -1544, -448, 290, -3336, -3336, + -650, -2731, -589, -3336, -3179, -3247, -765, -3336, -2911, -3199, + -2163, 90, -2516, -3336, -3336, 93, 17, -2209, -3336, -1772, + 63, -2203, -3336, -132, -2833, 94, 95, 1066, -3336, -2764, + 96, -919, -1241, -964, -1251, -3336, -76, -3336, -3336, 518, + 101, 1555, 2162, -3336, 23, -2263, -662, -603, -3336, -722, + -3336, -283, -3336, -642, -3336, -895, -649, -696, -3100, -1197, + -3336, 1820, -327, -3336, 719, -3336, -2748, -3336, -2984, -3336, + -3336, 702, -3336, 1237, 1238, -3336, -3336, -2356, 213, -628, + -2768, -2734, -2312, -938, 299, -633, 270, -2251, -1229, -3336, + 746, -3336, -607, -3336, -915, -1961, 109, -3336, -3336, 1703, + -928, -3336, 129, -604, -3336, -3336, -706, -3336, -3336, -3336, + -3336, -3336, -214, 132, -3336, 583, -3336, -2256, 585, -2245, + 1736, -637, -3336, 216, 22, 24, -3336, -3336, -3336, -3336, + -789, 666, -1917, -3336, -3336, -3336, -3336, 263, 1, 3190, + -36, -32, -3336, -19, -3336, -3336, -3336, 781, -3336, -3336, + 8, 47, 1900, -3336, -3336, -3336, -3336, -1013, -3336, -1882, + 814, -3336, 2063, 2070, -1822, -890, -40, 302, 825, -1710, + -2229, -588, 1303, 1886, 1891, -3336, 533, -2755, -3336, -558, + -3336, -665, -3336, -3336, -3336, 2056, -3336, 820, 1350, -1611, + -1582, -3336, -2284, -3336, -466, -294, -3336, -3336, -3336, -3336, + -3336, -2646, -2620, -449, 1318, -3336, 1896, -3336, -3336, -3336, + -3336, 205, -1596, 3100, 861, -3336, 9, -3336, -3336, -3336, + -3336, 195, -3336, 1059, -102, -3336, -431, -694, -815, 2127, + -75, 259, -1945, -17, -353, 576, -3336, -3336, 578, -2176, + -1474, 528, -210, 1056, -3336, -2383, -1619, -1547, -1540, -1230, + -3336, -3336, -792, 822, -3336, -3336, -3336, 833, 1019, -3336, + -3336, 2547, 2962, -3336, -932, 2976, 659, -1068, 2138, -968, + 2141, -971, -944, -908, 2142, 2146, 2150, 2151, 2156, 2168, + 2170, -1597, 5933, 373, -726, -2257, -3336, -1456, -1628, -3336, + -3336, -3336, 84, -3336, -1430, 137, -3336, -3336, -3336, -3336, + -2455, -3336, -442, -3336, -440, -3336, -3336, -3336, -1863, -3335, + -1900, -3336, 4186, 975, -3336, -3336, 508, -3336, -3336, -3336, + -3336, -1595, -3336, 7051, 875, -3336, -2130, -3336, -3336, -988, + -874, -1147, -1061, -1250, -2015, -3336, -3336, -3336, -3336, -3336, + -3336, -925, -1872, -218, 939, -3336, -3336, 1045, -3336, -3336, + -123, -1533, -1815, -2200, -3336, -3336, -3336, 946, 1669, 154, + -849, -1683, -3336, -1593, -3336, -3336, 994, -2532, -3336, -3336, + 504, -2801, -3336, -3336, 193, -3336, -712, -1154, -2617, 580, + 45, -3336, -854, -3084, -3336, -3336, -754, -2678, -1160, -934, + -3336, 133, -3336, 161, 136, -1757, -3336, 29, -3336, -401, + -3336, -3336, -2724, -3336, 138, 140, 2375, -3336, 1298, -3336, + -3336, -3336, -3336, -549, -3336, -648, 2199, -3336, -3336, 39, + -3336, 1797, -3336, 142, 286, -3336, 1111, -3336, 708, 143, + -3336, 2284, -438, 147, 1454, -3336, -3336, -3336, 25, -622, + 470, -3336, 1457, -3336, -3336, -703, -1714, -3336, 677, 1323, + -2166, 148, -3336, 492, 13, -3336, -3336, -3336, 86, 151, + 30, -3201, 152, -2880, -1763, -7, -3336, -3336, -3336, -669, + -3336, -3101 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -2183 +#define YYTABLE_NINF -2193 static const yytype_int16 yytable[] = { - 536, 934, 79, 53, 72, 887, 1194, 70, 1162, 732, - 71, 96, 1270, 1230, 1476, 101, 536, 57, 1290, 66, - 1861, 1056, 79, 84, 105, 2277, 983, 1862, 1402, 873, - 1533, 1385, 1348, 534, 731, 799, 1345, 1446, 1391, 1744, - 2244, 871, 900, 2039, 2014, 1845, 2513, 904, 2149, 534, - 793, 905, 1449, 2109, 2396, 1450, 1643, 533, 1469, 569, - 2767, 2077, 1834, 2161, 2405, 763, 985, 2089, 2200, 1448, - 536, 536, 1880, 832, 1828, 2179, 841, 2719, 2729, 3183, - 2328, 758, 2610, 1803, 50, 825, 2699, 51, 2701, 52, - 884, 884, 2177, 2178, 3180, 3150, 885, 2680, 3148, 2348, - 55, 2718, 1866, 534, 534, 924, 56, 915, 3197, 59, - 866, 1946, 1290, 2758, 60, 993, 1721, 61, 1657, 3201, - 2825, 1724, 2965, 1034, 2869, 2248, 64, 832, 832, 1059, - 67, 2423, 68, 1002, 1415, 69, 82, 2384, 83, 825, - 825, 2422, 85, 2427, 2591, 2592, -1428, 3038, 2392, 86, - 834, 3043, 2581, 2582, 2583, 2598, 1619, 1620, 920, 2602, - -505, 1080, 1080, 3280, 1269, 92, 1275, 2834, 1279, 3283, - 93, 95, -2021, 2202, 1633, 100, 104, 106, 2560, -926, - 548, 2818, -395, 836, -2021, -572, -1369, 1379, 1081, 2714, - 2032, 3635, -2169, -2169, -931, 2033, 1081, 2829, -931, -1369, - -1350, 1729, 1460, -2012, 834, 834, -2012, -1366, -1366, -934, - -2029, -2160, -2160, 2835, -576, 2125, 2843, 2339, -2178, -2178, - 3416, -934, -2155, -2155, 2806, 2297, -1370, 2809, 937, 2300, - -2029, -1370, 836, -893, -1367, -1367, 1080, -906, 1003, -921, - 2827, -1189, 836, 836, 1824, 3182, -535, 3756, 1653, -1189, - 3475, 2768, -2180, -2180, 938, 1864, 1395, 1878, 1725, 1395, - 836, 1080, 2630, 1290, 1080, 1677, 1281, 877, 1879, 2192, - 1679, 1991, 3507, 1824, 2972, 2192, 1993, 3350, 1804, 1219, - 901, 902, 1664, 895, 2797, 1846, -572, 3365, 1849, 1850, - 1370, 1028, 2419, 1752, -249, 1182, 2231, 3383, 549, -249, - 1222, 1687, 2885, 2887, 2232, 2890, 2714, 3592, 1624, 1379, - 1059, 552, 1766, 1493, 3172, -576, 2310, 2926, 1500, 3400, - 1503, 939, 1034, 2456, -1210, 1635, 3333, 3, 4, 1371, - -721, 2031, -1210, 897, 1181, 1689, 3403, 1284, 1179, 1528, - 2852, 836, 1026, 2241, 1991, 1881, 2570, 3520, 1992, 1993, - 940, 1409, 1035, 897, 896, 3705, 3420, 2761, 1802, 836, - 3639, 1767, 2769, 3712, 3729, 1002, 3551, 3202, 2083, 2031, - 1831, 1851, 3004, 1726, 3006, 553, 3552, 2528, 974, 3777, - 1798, 1799, 2896, -863, 854, 3481, 3796, 3483, 961, 2534, - 3347, 3053, 3361, 2272, 941, 1748, 1648, 3082, 3622, 3714, - 1215, 1209, 2571, 2303, 1812, 1856, 3359, 3698, 1629, 1677, - 3715, 1638, 2691, 1678, 1679, 2907, 3031, 2587, 3586, 2562, - 3587, 3318, 3716, 1677, 2333, 3603, 2567, 962, 3659, 1857, - 1768, 1520, 1677, 1639, 1012, 897, 1678, 1679, 3410, -2154, - -2154, 3382, 1885, 546, 3493, 1687, 891, 3775, 1958, 1927, - 891, 1991, 1041, 1080, 3425, 1992, 1993, 2588, 3411, 1687, - 1832, 3319, 1649, 1677, 2838, 1183, 3348, 1184, 1687, 1348, - 2603, 3494, 3083, 3052, 2603, 1763, 1560, 1217, 2273, 1689, - -572, 1769, 3360, 1521, 3032, 2334, 855, 2203, 1379, 1380, - 3604, 3717, 3737, 1689, 2762, 3685, 1036, 2242, 3688, 1727, - 1815, 3641, 1689, 1210, 2624, 3772, 3810, 1989, 1990, -576, - 1346, 3220, 1372, 2010, 1882, 3706, 2204, 965, 3564, 1852, - -863, 2304, 1243, 1246, 942, 2957, 3736, 1643, 1244, 3034, - 1853, 3518, 2758, 1689, 2758, 943, 1285, 3203, 892, 2897, - 3593, 3778, 892, 804, 3707, 3553, 3713, 1770, 1175, 3532, - 2572, 3621, -572, 3797, 949, 3502, 2612, 3362, 2420, 3084, - 1499, 1749, 1637, 557, 1884, 992, 1960, 3309, 3536, 3311, - 803, 1080, 944, 2649, 3512, 1833, 2811, 2812, 2813, 893, - 3233, -576, 1833, 1805, 2080, 3173, 1764, 2770, 3397, 2771, - 898, 560, 2819, 2820, 2200, 1009, 945, 3764, 732, 1668, - 2311, 1865, -475, 3210, 3770, 1384, 2023, 3508, 2119, 2606, - 1800, 1380, 969, 1619, 1620, -1189, 3193, 3422, 1871, 2772, - 878, 2411, 3492, 971, 2149, 946, 3351, 3496, 2404, 3724, - 2798, 1801, 1373, 1245, 2205, 1739, 932, 3165, 1633, 2408, - 933, 3760, 838, 983, 2207, 2926, 2040, 2193, 1948, 3211, - 3686, 1615, 550, 2682, 1952, 1381, 3187, 3757, 2652, 3580, - 3528, 835, 1747, 3224, 1817, 1751, 2839, 2805, 2064, 2703, - 2233, 2721, 3374, 3375, 2836, -572, 1862, -1428, 2984, 2940, - 2846, 2507, 2920, 2908, 2909, 2910, 2911, 2247, 2727, 1949, - 3150, -505, -505, 3148, 2894, -2021, 1638, 975, -1210, 2202, - 2131, 2132, -926, 1630, -576, 3730, 2821, -2021, 1638, -1369, - 1344, 1124, 1125, -395, -572, 1630, -572, -931, 1639, 1124, - 1125, 932, -1369, -1350, 3378, 933, -2012, 887, 1384, -2012, - 1639, 2297, 1640, -2029, 2732, 2810, 929, 1621, 2116, 1653, - 3718, 1956, 3499, -576, 1642, -576, 3464, 3500, 1653, -1370, - 1290, 2173, 1290, -2029, -1370, 1672, 1622, 2825, 3476, 1002, - 1627, 1001, -921, 2152, 3341, 1722, 2249, 1022, 1624, 79, - 1185, 1399, 1400, 3620, 1399, 1400, 3673, 1384, 1710, 887, - 1856, 2054, 799, 3687, 2008, 2029, 1818, 894, 1635, 932, - 1380, 2625, 3627, 1665, 1246, 2174, 3442, 3628, 998, 2533, - 1243, 2208, 536, 2071, 1857, 3025, 1244, 988, 2333, -249, - -249, 3765, 2209, 536, 1176, 3414, 2522, 116, 1040, 1079, - 536, 2523, 1991, 2107, 2404, 880, 1992, 1993, 3018, 107, - 2561, -2183, -2183, -2183, 2789, 534, 3444, 2707, 2771, 2339, - 904, 3720, 1638, 951, 905, 952, 534, 2790, 3062, 536, - 536, 3655, 3656, 534, 2005, 2006, 2007, 2008, 1248, 832, - 3417, 1766, 3332, 2708, 1639, 3721, 1180, 3415, 3095, 2755, - 832, 1231, 2568, 536, 3063, 3418, 2372, 832, 1640, 3005, - 108, 2524, 1024, 3696, 3019, 1180, 2375, 3180, 889, 2378, - 1249, 1177, 79, 53, 72, 2870, 110, 70, 3228, 3766, - 71, 96, 117, 1331, 1074, 101, 3700, 57, 1186, 66, - 1767, 1245, 1064, 84, 105, 3674, 111, 2568, 3334, 1707, - 1708, 1709, 1710, 1065, 3519, 536, 732, 884, 3767, 1337, - 536, 1947, 1195, 2371, 866, 866, 834, 866, 1824, 866, - 1705, 1706, 1707, 1708, 1709, 1710, 2541, 834, 3411, 1825, - 1215, 953, 874, 954, 834, 1216, 2195, 1505, 3401, 2003, - 2004, 2005, 2006, 2007, 2008, 1250, 2730, -741, 2824, 1824, - 2692, 1080, 3150, 2927, 50, 3148, 890, 51, 2497, 52, - 1827, 906, 1337, 3290, 2433, 3166, 3167, 2397, 2398, 2399, - 55, 2506, 111, 1001, 2575, 2508, 56, 887, 2510, 59, - 536, 536, 3675, 1391, 60, 79, 536, 61, 118, 536, - 536, 2936, 536, 536, 536, 536, 64, 3798, 799, 1347, - 67, 3050, 68, 1025, 907, 69, 82, 1217, 83, 536, - 1769, 536, 85, 2535, 2536, 2537, 2538, 2539, 2540, 86, - 536, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, - 2553, 3099, 2149, 2325, 909, 92, 3801, 536, 1337, 1607, - 93, 95, 534, 3505, 534, 100, 104, 106, 928, 1256, - 3159, 3419, 1246, 534, 2765, 3785, 3066, 1215, 1218, 536, - 1631, 1632, 887, 3792, 2975, 2370, 832, -659, 832, 1257, - 112, 932, -659, 2542, 1045, 933, 1770, 832, 825, 536, - 1024, 113, 2704, 2543, 2705, 2381, 3367, 927, 1999, 825, - 2388, 536, 536, 536, 3372, 536, 536, 1243, 732, 3069, - 836, 2373, 1900, 1244, 1668, 2014, 2376, 2039, 1862, 23, - 1046, 3488, 1247, 2215, 3802, 1258, 1248, 1638, 114, 959, - 2117, -2149, -2149, 1658, 3056, 1835, 1506, 2814, 2738, 2123, - 1243, 536, 2566, 3616, 1217, 1393, 1244, 1048, 1394, 1639, - 1947, 1901, -2021, 834, -659, 834, 112, 552, 1249, 536, - 536, 2521, 3300, 1642, 834, 2525, 1505, 113, 2527, 1754, - 1755, 932, 1761, 905, 905, 1665, 905, 3146, 930, 2672, - 1508, 115, -1414, 936, 1180, 2235, 1515, 1180, 3405, 2236, - 948, 2727, 1432, 1433, 1737, 1218, 536, 1738, 2799, 3537, - 536, 536, 960, 1836, 114, -659, -2150, -2150, 2673, 3599, - 536, 536, 536, 1953, 552, 536, 1954, 3436, 1245, 3803, - 2456, 553, 1259, 3057, 2667, 2668, 932, 1657, -1350, 1496, - 933, 1025, 884, 1250, 2628, 2022, 955, 2024, 2025, 1607, - 1512, 1904, 1169, 1170, 967, 1172, 2079, 1174, 2216, 2080, - 3396, 1245, 2853, 1863, 3538, 1513, -225, 115, 2105, 1518, - 972, 2106, 2864, 3539, 973, 2217, 26, 27, 28, 2416, - 2218, 3510, 2417, 1260, 958, 1337, 3073, 991, 553, 1052, - 1068, 1069, 1070, 976, 1261, 1073, 1337, 3540, 1613, 977, - 46, 2927, 3058, 1837, 3059, 978, 1262, 2516, 1507, 2554, - 2517, 979, 2555, 1045, 961, 3342, 2448, 2604, 2449, 2219, - 2605, 1337, 1438, 1439, 2670, 120, -2183, -2183, -2183, 547, - 2003, 2004, 2005, 2006, 2007, 2008, 3074, 762, 1263, 2607, - 989, 2674, 2605, 33, 2785, 2791, 2675, 2786, 2792, 1046, - 3391, 853, 1007, 962, 3075, 867, 2700, 1838, 1009, 2807, - 2867, 732, 2517, 2868, 1008, 1514, 556, 1908, 1010, 1909, - 732, 3541, 1013, 1911, 1912, 3276, 1048, 2933, 959, 2824, - 2605, 2576, 38, 2577, 3542, 1016, 1941, 1001, 3804, 1246, - 963, 1017, 2779, 1265, 2781, 79, 2934, 2937, 2939, 2106, - 2938, 2938, 3026, 3190, 732, 3027, 3191, 3268, 799, 536, - 3270, 836, 3272, 3192, 964, 1018, 2417, 40, 1266, 557, - 1005, 992, 1246, 3230, 998, 1833, 3231, 1019, 43, 1963, - 1950, 3291, 1951, 3386, 2106, 3229, 2275, 2921, 2578, 1268, - 2579, 2928, 1020, 965, 559, 2149, 895, 560, 2782, 1273, - 2784, 960, 1063, 1248, 3049, 1021, 3051, 2109, 3076, 536, - 536, -660, 1212, 2741, 1214, 536, -660, 536, 3077, 1022, - 2658, 1027, 536, 536, 536, 536, 557, 1171, 992, 2220, - 3794, 3437, 1277, 46, 2106, 1274, 1248, 536, 536, 3438, - 3470, 1029, 2605, 2106, 1061, 2870, 1066, 536, 3477, 536, - 534, 2080, 536, 2676, 560, -2151, -2151, 536, 1052, 536, - 536, 1071, 536, 1072, 2677, 2833, 536, 896, 1278, 3489, - -2152, -2152, 3490, 3086, 832, 3526, 838, 1507, 3191, 3093, - 534, 1075, 534, 14, 15, 534, 3739, 1074, -660, 3773, - 534, 3774, 1173, 534, 3527, 534, 1196, 2417, 1189, 534, - 1835, 3751, 3561, 1900, 832, 2106, 832, 3726, 3625, 832, - 1250, 3191, 3637, 1197, 832, 3638, 825, 832, 825, 832, - 1199, 825, 1607, 832, 3667, 3176, 825, 3668, 1203, 825, - 23, 825, -2156, -2156, 3085, 825, 3094, 2958, 2959, -660, - 1200, 3543, 1901, 1250, 3544, 1201, 2339, 1213, 897, 1204, - 3809, 834, 2456, 1206, 3711, 536, 536, 3638, 3618, -2157, - -2157, 79, 2108, 2112, 536, 536, 2110, 1401, 1836, 2111, - 2114, -2158, -2158, 536, 2115, 3805, 1232, 1444, 1235, 1902, - 536, 834, 3771, 834, 1237, 3638, 834, 536, 3808, 3806, - 1238, 834, 3490, 1239, 834, 1240, 834, 2944, 1657, -1902, - 834, 3582, 3583, 1903, -2159, -2159, 1242, 536, 732, -2161, - -2161, 116, 536, 2946, 2948, 536, 2947, 2949, 2950, 3463, + 536, 72, 934, 1270, 1533, 983, 1194, 1162, 79, 732, + 887, 53, 1345, 101, 1230, 1056, 536, 57, 1290, 1862, + 731, 873, 70, 66, 71, 96, 1845, 1861, 79, 84, + 105, 1476, 2083, 799, 2039, 900, 1402, 2246, 871, 1448, + 1348, 2151, 1446, 1744, 2014, 2514, 1643, 904, 985, 2279, + 2732, 1834, 534, 2077, 2091, 1391, 2163, 1385, 2181, 793, + 905, 2330, 2399, 2408, 2202, 2111, 1449, 2611, 534, 2722, + 536, 536, 2702, 1803, 2704, 1828, 2179, 2180, 1880, 2350, + 758, 1946, 2770, 50, 2683, 2761, 901, 902, 51, 52, + 55, 533, 885, 56, 59, 60, 61, 924, 3166, 1002, + 3139, 64, 1450, 1866, 915, 2721, 3156, 832, 2829, 67, + 2592, 2593, 1290, 3142, 1269, 2874, 1275, 2387, 1279, 993, + 866, 2599, 534, 534, 2972, 2603, 3045, 2426, 2250, 68, + 3050, 1034, 69, 82, 1415, 1657, 83, 1059, 85, 2430, + 86, 2425, 92, 93, -399, 2561, 1404, 95, 100, 1721, + -511, 104, 106, -1438, 1724, 1619, 1620, -578, 2395, 2204, + 834, 832, 832, 2582, 2583, 2584, 2299, 2087, -1360, 3250, + 2612, -2031, 3380, 1633, -582, 3247, 2822, 2838, 836, -2179, + -2179, 2032, 548, 1081, 1379, -2031, 2033, 1081, 2839, 2847, + -1379, -936, -1379, 836, -2022, -2022, 1460, 2302, -1376, -1376, + 2341, -941, -2170, -2170, -2039, -941, 836, -2039, -1380, 1729, + 1080, -1380, -2188, -2188, 834, 834, -1377, -1377, 1080, 2833, + -903, 1812, 1991, 2831, -916, 1281, 1664, 1993, 825, 2810, + -931, 1878, 836, -944, 836, -944, 877, 2771, 2194, -2165, + -2165, 3317, 1879, 2194, 1003, -2190, -2190, 3532, 1653, 1725, + 1395, 836, 1395, 1181, 2813, 1080, 2127, 1080, -578, 3472, + 3367, 1080, -1199, 1290, 3530, 2979, 23, 3131, 3440, 1752, + -1199, 2633, 1677, 2890, 2892, -582, 2895, 1679, 1804, 110, + 3559, -541, 825, 825, -249, 1766, 3384, 1824, 1674, -249, + 3736, 1470, 1028, 1846, 836, 2233, 1849, 1850, 1864, 1624, + 549, 3737, 1379, 2234, 3364, 3300, 2457, 891, 1687, 1379, + 2717, 1219, 1182, 3738, 1370, 3332, 1635, 1815, 1059, 1404, + 3141, 2205, 3608, 1677, 3161, 2571, 3822, 1678, 1679, 2422, + 1034, 1002, -727, 1991, 1767, 2031, 897, 1992, 1993, 1179, + 3638, 2931, 1689, 2717, 3, 4, 3693, 3655, 2772, 2084, + 2206, 974, 1824, 1371, 1284, 1409, 2856, 1991, 1802, 1687, + 2529, 1992, 1993, 2801, 1726, 3276, 116, 3278, 3781, 1493, + 1831, 1881, 2535, 2031, 1500, 111, 1503, 2901, 891, 1798, + 1799, 2572, 3739, 897, 3567, 3751, 3089, 3734, 3803, 1026, + 1629, -2164, -2164, 1689, 3568, 1528, 2764, 3659, 1035, 892, + 2912, 3167, 2563, 1404, 3060, 1763, 1404, 1404, -1220, 2568, + 3679, 3328, 3720, 26, 27, 28, -1220, 1215, 3011, 3375, + 3013, 3562, 2694, 854, 3314, 1927, 1209, 3374, 1677, 1677, + 3632, 3801, 1678, 1679, 3326, 1520, 3563, 1648, 2274, 3025, + 893, 3707, 1677, 1885, 2217, 2335, 2857, 2335, 3710, 3389, + 1222, 117, -578, 2604, 1769, 1856, 1012, 2604, 2793, 3378, + 1832, 3090, 1175, 3038, 1687, 1687, 2119, 1560, 2207, -582, + 892, 2794, 1064, 2411, 1041, 2125, 107, 1348, 2209, 1857, + 33, 1817, 1183, 1065, 1184, 3694, 1380, 1521, 2774, 2627, + 1727, 3836, 1781, 3823, 1217, 3026, 3059, 3548, 1689, 1689, + 3315, 1470, 3041, 1649, 804, 2761, 2336, 2761, 2758, 1246, + 3327, 3379, 1689, 2964, 3761, 3798, 1764, 1643, 3102, 38, + 1770, 803, 2312, 2275, -578, 855, 3185, 108, 1210, 2573, + 2858, 3039, 2859, 2765, 2902, 3762, 1372, 3705, 3132, 3544, + 1882, -582, 1036, 3467, 2614, 1959, 1961, 1009, 3091, 112, + 3804, 949, 3406, 1285, 40, 3609, 3637, 118, 3796, 1833, + 113, 3457, 3477, 3569, 1637, 43, 3461, 1884, 2652, 2218, + 3735, 3168, 3695, 2773, 2414, 2774, 3329, 1871, 2815, 2816, + 2817, 1747, 1833, 1805, 1751, 3532, 2219, 2823, 2824, 878, + 3318, 2220, 2202, 569, 3473, 2423, 1384, 114, 732, 763, + 1668, 2607, 3530, 1818, 1380, 2775, 2023, 1499, 3760, 971, + 841, 1380, 1619, 1620, 2080, 3175, 2195, 2121, 3540, 2151, + 46, 2685, 983, 3361, 884, 884, 3176, 1948, 3198, 3596, + 2221, 3740, 3564, 1952, 2407, 2210, -1199, 1633, 3189, 3152, + 3146, 1739, 1800, 3124, 1865, 2040, 2211, -578, 894, 2925, + 115, 2508, 1381, 3386, 550, 2706, 1373, 2088, 2655, 3708, + 2088, 2249, 2899, 1615, -582, 2843, 2991, 2064, 1862, 2235, + 975, 1949, 1344, 2931, 2299, -399, 2724, 2840, 3785, 2850, + 2809, -511, -511, 2730, -1438, 3464, -578, 2204, -578, 932, + 3465, -1360, 920, 933, -2031, 2913, 2914, 2915, 2916, 2133, + 2134, 2825, 1630, -582, 2735, -582, 1124, 1125, -2031, 2802, + 1124, 1125, 3429, -1379, -936, -1379, 1630, -2022, -2022, 2628, + 1638, 3345, 1638, -481, -941, 1002, 3752, -2039, 1176, 1672, + -2039, -1380, 887, 932, -1380, 2008, 2947, 1665, 2118, 1653, + 1470, 1470, 1639, 1622, 1639, 1956, 1470, 1627, 1653, 2829, + 1290, 2175, 1290, -931, 1621, 1722, 1640, 2251, 1642, 1624, + 1022, 1001, 2814, 2154, 3709, 1399, 1400, 1399, 1400, 1384, + 1856, 3341, 3342, 2126, 3032, 79, 3441, 1384, 3782, 1635, + 799, 1801, -1220, 3644, 887, 1710, 2157, 1185, 2158, 1851, + 2222, 3308, 932, 2029, 1857, 2176, 933, 1243, 3643, -249, + -249, 1748, 536, 1244, 3827, 1177, 2313, 998, 1215, 2542, + 1040, 3063, 3408, 536, 2109, 3636, -869, 2177, 1074, 546, + 536, 3446, 3789, 3448, 3619, 2341, 3602, 2243, 3603, 1025, + 2407, 1705, 1706, 1707, 1708, 1709, 1710, 2054, 2588, 1638, + 904, 2003, 2004, 2005, 2006, 2007, 2008, 3675, 3676, 536, + 536, 1824, 3633, 905, 534, 3285, 895, 1393, 1180, 2071, + 1394, 1639, 1825, 3458, 1231, 534, 3811, 2005, 2006, 2007, + 2008, 3299, 534, 536, 3818, 1640, 2569, 1180, 2589, 2875, + 1638, 3012, 3828, 3727, 2375, 1217, 552, 3365, 3193, 3620, + 3459, 72, 959, 832, 2378, 3286, 1331, 2381, 79, 835, + 3064, 53, 1639, 101, 832, 3139, 3722, 57, 1245, 874, + 3301, 832, 70, 66, 71, 96, 1642, 1186, 890, 84, + 105, 2569, 2298, 2298, 2374, 536, 732, 896, 1195, 1337, + 536, 2305, 880, 3718, 2675, 2197, 1218, 1852, 1707, 1708, + 1709, 1710, 2695, -747, 866, 866, 834, 866, 1853, 866, + 553, 3580, 1243, -869, 3702, 1243, 2543, 834, 1244, 889, + 3661, 1244, 2828, 2676, 834, 960, 2544, 1749, 1508, 3065, + 2932, 3066, 3375, 50, 1515, 3257, 1824, 3829, 51, 52, + 55, 2244, 1337, 56, 59, 60, 61, 1827, 2400, 2401, + 2402, 64, 2436, 1001, 1404, 2498, 2942, 3125, 3126, 67, + 536, 536, 887, 2327, 1404, 3057, 536, 1404, 897, 536, + 536, 79, 536, 536, 536, 536, 799, 2507, 1347, 68, + 1391, 2509, 69, 82, 2511, 1024, 83, 2576, 85, 536, + 86, 536, 92, 93, 3106, 2373, 3790, 95, 100, 2288, + 536, 104, 106, 3728, 959, 1496, 2768, 1025, 2151, 2306, + 3470, 2205, 2710, 1638, 3118, 2384, 1512, 536, 1337, 1607, + 2391, 906, 2534, 1245, 552, 961, 1245, 961, 111, 1246, + 552, 2982, 3729, 3824, 3742, 1639, 3069, 2523, 2711, 536, + 2206, 534, 2524, 534, 927, 1346, 2677, 887, 3453, 1835, + 3703, 2678, 534, 2562, 2707, -1424, 2708, 1947, 3743, 536, + 2376, 1760, 3070, 1958, 962, 2379, 962, 907, 1080, 1432, + 1433, 536, 536, 536, 552, 536, 536, 960, 732, 2039, + 832, 909, 832, 1862, 3791, 1668, 2014, 3334, 553, 1658, + 928, 832, 1215, 1248, 553, 3339, 3830, 1216, 557, -1424, + 992, 2842, 2525, 963, 1169, 1170, 969, 1172, 3757, 1174, + 836, 536, 2567, 3792, 2741, 1947, 2818, 1836, 1424, 1425, + 1505, 1631, 1632, 898, 932, 1249, 560, 964, 933, 536, + 536, 1256, 552, 834, 951, 834, 952, 3400, 553, 1754, + 1755, 2522, 1761, 930, 834, 2526, 1180, 3267, 2528, 1180, + 2435, 1257, 905, 905, 965, 905, 965, 932, 2207, 1243, + -2031, 1665, 3073, 2208, 3615, 1244, 536, 936, 2209, 1217, + 536, 536, 2803, 1737, 948, 23, 1738, 2457, 3360, 1900, + 536, 536, 536, 1953, 1246, 536, 1954, 1246, -665, 1438, + 1439, 1432, 1433, -665, 991, 955, 553, 1258, 2622, 1960, + 1250, 825, 112, 1024, 1080, 3076, 2631, 1837, 2679, 1607, + 2237, -225, 825, 113, 2238, 1863, 1657, 958, 1901, 2680, + 1218, 2022, 2869, 2024, 2025, 1766, 1470, 1470, 1470, 1470, + 1470, 1470, -2159, -2159, 1470, 1470, 1470, 1470, 1470, 1470, + 1470, 1470, 1470, 1470, 1247, 1337, 1079, 1273, 1248, 1991, + 114, 1248, 967, 1992, 1993, 1902, 1337, 1045, -2193, -2193, + -2193, 1838, 2932, 3309, 2733, -665, 1900, 1513, 3355, 1080, + 1245, 1518, 555, 556, 1767, 953, 557, 954, 992, 1903, + 1249, 1337, 557, 1274, 992, 932, 2673, -1360, 1613, 933, + 46, 972, 1835, 1046, 1259, 1068, 1069, 1070, 976, 2079, + 1073, 988, 2080, 115, 560, 1901, 973, 559, 1904, 1506, + 560, 1438, 1439, -2160, -2160, 2107, -665, 838, 2108, 2703, + 1048, 732, 26, 27, 28, 2210, 557, 1908, 992, 1833, + 732, 1346, 1941, 1909, 2828, 3243, 2211, 977, -224, 1911, + 1912, 2419, 3369, 1768, 2420, 1260, 2517, 1001, 978, 2518, + 1469, 559, -2161, -2161, 560, 1250, 1261, 2705, 1250, 3233, + 1836, 79, 979, 3236, 732, 3238, 799, 3475, 1262, 536, + 2555, 2605, 3080, 2556, 2606, 1963, -2162, -2162, 2608, 1243, + 2782, 2606, 2784, 989, 557, 1244, 558, -2166, -2166, 33, + 2734, 2734, 3194, 998, 1769, 1904, 2788, 1009, 2795, 2789, + 1263, 2796, 2926, 1018, 2811, 2151, 2933, 2518, 1007, 1243, + 2872, 929, 560, 2873, 2661, 1244, 2785, 1008, 2787, 536, + 536, 884, 3081, 1860, 2744, 536, 1010, 536, 38, 1470, + 1470, 1246, 536, 536, 536, 536, 2111, 1029, 2938, 2939, + 3082, 2606, 2108, 2943, 1013, 2875, 2944, 536, 536, 2577, + 1837, 2578, 1052, 2945, 2837, 1265, 2944, 536, 3033, 536, + 1770, 3034, 536, 40, 2579, 3149, 2580, 536, 3150, 536, + 536, 1507, 536, 2055, 43, 2056, 536, 1016, 2058, 534, + 1266, -2167, -2167, 2062, 3100, 3820, 2065, 3056, 2066, 3058, + 1245, 1277, 2070, 3093, 3799, 1248, 3800, 3151, 2341, 1243, + 2420, 1268, 3764, 3195, 1838, 1244, 3196, -2168, -2168, 534, + 2457, 534, 3258, 3350, 534, 2108, 2277, 3776, 832, 534, + 1245, 120, 534, 3401, 534, 547, 2108, 1278, 534, 46, + -2169, -2169, 1607, 762, 1017, 1999, 3092, 1835, 3101, 3402, + 2965, 2966, 2606, 1019, 3083, 1470, 3135, 853, 832, 3435, + 832, 867, 2108, 832, 3084, 1020, 3835, 3442, 832, 3454, + 2080, 832, 3455, 832, 1021, 536, 536, 832, -2171, -2171, + 2114, 834, 1833, 1022, 536, 536, 1027, 79, 3428, 3634, + 2110, 1066, 2117, 536, 3598, 3599, 1835, -2172, -2172, 3538, + 536, 2112, 3150, 2113, 2116, 3831, 3539, 536, 1061, 2420, + 1071, 834, 1250, 834, 3577, 1836, 834, 2108, 3834, 3641, + 1245, 834, 3150, 2952, 834, 2951, 834, 536, 732, 3748, + 834, 3162, 536, 3657, 3687, 536, 3658, 3688, 1657, 1072, 1607, 536, 536, 536, 536, 536, 536, 536, 536, 732, - 2945, 1860, 1904, 536, 536, 536, -2162, -2162, 536, 1331, - 1241, 552, 536, -2163, -2163, 536, 536, 536, 536, 536, - 536, 536, 536, 536, 2189, 1254, 536, 2055, 1837, 2056, - -2164, -2164, 2058, 536, 1255, 1337, -1414, 2062, 534, 1272, - 2065, 1276, 2066, 2988, 2989, 1835, 2070, 26, 27, 28, - 2279, -2165, -2165, 536, 905, 1424, 1425, -2166, -2166, -2167, - -2167, -2168, -2168, -2170, -2170, -2171, -2171, 2298, 2299, 1670, - -1902, 1835, 1280, 898, 1282, 553, -2172, -2172, 536, 1673, - 1340, 1243, 1838, -2173, -2173, 1344, 2133, 1244, 1186, 536, - 536, -716, -716, 2134, 2135, 1343, 2880, 1349, 2136, 2137, - 2138, 1723, 3146, -2174, -2174, -2175, -2175, -2177, -2177, 1354, - 1728, 1243, 1366, 1836, 33, 1369, 2727, 1244, -1902, -2179, - -2179, -2182, -2182, 2173, 1368, 35, 2244, 1376, 1432, 1433, - 2203, 2432, 1607, -1902, 1887, 1888, -720, -720, -1902, 1836, - -719, -719, 732, -1902, 1434, 1435, 732, 1438, 1439, 37, - 1833, 1387, -1902, 38, 3214, 3215, 1377, -1902, 1383, 2204, - 1386, 1079, 3338, 3339, 1991, 3758, 3761, 2354, 1992, 1993, - 1392, 2360, 3093, 1994, 1995, 1996, 1867, 2872, 2874, 1410, - 2329, 3747, 3748, 3783, 3784, 1733, 1734, 732, 40, -1902, - 536, 2343, 1245, 2346, 2746, 2747, 2357, 1337, 1411, 43, - 536, 536, 1870, 1837, 1416, 1474, 2365, 1487, 2367, 552, - -1902, 1489, 1963, 1490, 3042, 1501, 44, 1497, 1872, 1509, - 1510, 2374, 1245, 1760, 1516, 1517, 2377, 1527, 1523, 1837, - 2382, 2383, 1529, 2385, 3184, 2389, 2390, 2497, 1607, 3153, - 45, 2083, 2498, 3171, 1609, -897, 3223, 2452, 1438, 1439, - 1610, 1612, -904, 1243, 46, 1621, 3225, 1838, 1625, 1244, - 732, -1902, 46, 557, -1902, 992, -741, 1337, 536, 3208, - -1902, -742, -894, 553, -895, 1636, 536, 2205, -898, 1637, - 3738, 3302, 2206, 1838, 3740, -896, 1644, 2207, 559, 1669, - 1659, 560, 1607, 1835, 1716, 1671, 536, 536, 1718, 536, - 1720, 1732, 1740, 1741, 1607, 536, 536, 536, 536, 536, - 536, -1902, 1745, 536, 536, 536, 536, 536, 536, 536, - 536, 536, 536, 1750, 3560, 1833, 1753, 1216, 536, 536, - 1788, 1218, 536, 1790, 1607, 1792, -1902, 23, 1808, 536, - 1810, 1607, 1829, 1830, 1840, 1841, 1842, 1962, 1847, 555, - 1854, 1833, 1855, 1246, 1997, 1877, 1859, 1869, 3799, 1890, - 1835, 1836, 1874, 536, 1245, 1891, 1079, 1896, 1899, 1991, - 536, 1906, 536, 1992, 1993, 2726, 536, 1998, 1994, 1995, - 1996, 1892, 1913, 1246, 3146, 1607, -585, 1907, 1914, 1607, - 1917, 536, 1923, 1337, 11, 1607, 874, 1920, 2727, 1921, - 1924, -585, 1925, 534, 1926, 1928, -585, 1929, 1346, 534, - 1942, 1947, 1943, 2324, 1955, -224, 1983, 1248, 2019, 1607, - 1980, 1982, 14, 15, 2796, -1902, 1985, 832, 1836, 2030, - 3358, 536, 536, 832, 3370, 2050, -1902, 1988, 536, 825, - 2011, 1404, 2020, 2379, 2208, 825, 2057, 1248, 2027, 1249, - 1999, 1837, 2052, 2067, 2053, 2209, -1902, -585, -1902, -1902, - 2063, 557, 1604, 558, 3379, 3380, 2068, 2069, 2075, 23, - 3524, 536, 1622, 2081, 2078, 536, 1615, 887, -585, 2380, - 536, 536, 1627, 3560, 26, 27, 28, 2082, 2084, 560, - 2085, 2800, 2088, 2086, 2119, -1902, 2118, 1080, -1902, -1902, - -1902, 1677, 2153, 1835, 834, 1838, 536, 536, 2158, 2154, - 834, 536, 2162, 2165, 2168, 2167, 2169, 3267, 1837, 2191, - 2039, 2211, 2170, 2214, 1250, 1246, 2238, 536, 3560, -585, - 536, 536, 536, 2212, 2239, 2257, 2245, 2259, -585, 2258, - 2260, 2261, 2265, 896, 2275, 2278, 2287, 2288, 536, 732, - 2289, 33, 2292, 2290, 1250, 536, -1904, 1657, 536, 2312, - 2291, 2313, 1042, 2309, 534, 2317, 2314, 1043, 2322, 1730, - 2326, 1836, 1838, 1833, 536, 2330, 2331, 2332, 536, 2340, - 2593, 3560, 1998, 1674, 897, 2386, 2596, 3435, 536, 1248, - 38, 534, 2358, 2139, 2140, 2141, 2359, 2142, 2143, 2144, - 2145, 2146, 2147, 2400, 2363, 536, 536, 534, 2364, 2401, - 2414, 534, 2418, 2424, 1404, 832, 26, 27, 28, 3576, - 2402, 2387, 536, 1950, 536, 40, 1044, 825, 2434, 2435, - 2438, 832, 2436, 2437, 2804, 832, 43, 2439, 2453, 536, - 1833, 2457, 2458, 825, 2501, 2460, 2499, 825, 2500, 2503, - 2502, 2505, 1604, 732, 3356, 1999, 2518, -1904, 2509, 2526, - 2016, 1837, 732, 732, 732, 1991, 2556, 2250, 2000, 2001, - 2002, 2015, 2003, 2004, 2005, 2006, 2007, 2008, 2563, 2564, - 2585, 2597, 2573, 33, 2565, 2569, 2609, 2354, 2354, 2354, - 2574, 46, 834, -585, 35, 2595, 1250, 2611, 1404, 1045, - 2616, 1404, 1404, 2617, 3020, -1904, 2618, 536, 834, 2627, - 2626, -585, 834, 2634, 2635, 1838, 1337, 23, 37, 2620, - -1904, 2638, 38, 2639, 2621, -1904, -585, 2622, 2640, 2623, - -1904, -585, 2643, 2641, 2642, 1046, 2644, 2645, 2656, -1904, - 2646, 2319, 2321, 39, -1904, 1676, 1862, 1649, 1677, 732, - 2652, 1047, 1678, 1679, 1607, 2666, 2663, 40, 2664, 1908, - 23, 1909, 1048, 932, 2671, 1911, 1912, 933, 43, 2687, - 3513, 2678, 2711, 2688, 2840, 2695, -1904, 2693, 2714, 2694, - 2706, 2713, -585, 1833, 1687, 44, 2737, 2740, 2716, 2720, - 2723, -2183, -722, 2722, 2733, 2734, 2736, -1904, 1049, 2744, - 2745, 3066, 2751, -585, 1805, 2748, 2749, 3067, 2391, 45, - 1607, 2757, 2754, 2778, 536, 2780, 2795, 2857, 1689, 1229, - 3068, 2753, 2793, 46, 2801, 2794, 2409, 2409, 2802, 1668, - 732, 2803, 2815, 2816, 2830, 2831, 2832, 2855, 2837, 2850, - 1959, 1961, 2854, 2851, 3069, 1050, 3070, 2858, -1904, 2861, - 2865, -1904, 1051, 1042, -585, 1963, 1833, -1904, 1043, 2877, - 2884, 2892, 2895, -585, 26, 27, 28, 2898, 536, 2901, - 2915, 2902, 2916, 2000, 2001, 2002, 2903, 2003, 2004, 2005, - 2006, 2007, 2008, 2918, 1596, 2904, 2929, 2930, 2919, 3565, - 2935, 3567, 2173, 2954, 1052, 3021, 2943, 2951, -1904, 2982, - 2983, 534, 2962, 2961, 2980, 2995, 2520, 26, 27, 28, - 536, 2986, 3003, 1053, 2996, 3001, -2183, 1044, 3007, 3012, - 3013, 3015, 3033, -1904, 3035, 832, 1607, 3575, 3037, 3039, - 3048, 33, 887, -2183, 3054, 3071, 1180, 3055, -2183, 3061, - 3081, 3168, 3169, 536, 3097, 3170, 3178, 3174, 3179, 3194, - 536, 536, 3195, 3200, 3204, 3216, 3217, 2417, 3226, 3221, - 3227, 3252, 3232, 3255, 3259, 3263, 536, 887, 3704, 3577, - 38, 3579, 3273, 3274, 33, 1604, 3277, -2183, 3278, 536, - 2998, 3317, 536, 874, 536, 3303, 1054, 3310, 3313, 3314, - 1045, 1607, 536, 3324, 3335, 536, 536, 3326, 3331, 3336, - 536, 536, 834, 3345, 3665, 40, 3072, 536, 3337, 3343, - 3349, 3073, -1904, 38, 3654, 3353, 43, 3669, -585, 3354, - 3363, 3041, 3355, -1904, 536, 3366, 1046, 3368, 3369, 3344, - 3373, -2148, 3384, 44, 1698, 536, -2149, -2150, 3385, 3024, - -2151, 3387, 1047, -1904, -2152, -1904, -1904, -2153, 40, -2154, - 3649, -2155, 3388, 1048, 3389, 536, -2156, 45, -2157, 43, - -2158, 3074, 3404, -2159, -2161, -2162, 3406, -2163, 2124, 3407, - -2164, 46, 3421, 1604, 1596, -2165, 44, -2166, 3390, 3075, - -2167, 2155, -1904, 2156, 3392, -1904, -1904, -1904, 932, 1049, - -2168, 1199, 933, -2170, -2171, -2172, -2173, -2174, -2175, 732, - 45, -2176, 3149, 732, -2177, 732, 536, 536, -2178, -2179, - -2180, 3044, 2175, -2181, 3022, 3046, 3424, -2182, -1367, 3426, - 3393, 536, 536, 3402, 2354, 3423, 3408, 3430, 3151, 3431, - 2360, 1256, 3434, 3439, 536, 3440, 1050, -2183, 3443, 3445, - 887, 3451, 3454, 1051, 3098, 1607, 3447, 3457, 3453, 3458, - 3459, 1257, 3466, 536, 3219, 3181, 3465, 3462, 3487, 3469, - 3485, 3155, 3156, 3157, 3158, 3486, 3160, 3161, 3162, 3163, - 3164, 3491, 3498, 1908, 3501, 1909, 532, 543, 3503, 1911, - 1912, 2498, 567, 3076, 3515, 1052, 3516, 3525, 567, 3209, - -1366, 3523, 822, 3077, 837, 3531, 3533, 1258, 840, 567, - 849, 887, 3534, 849, 1053, 3547, 869, 869, 536, 3550, - 869, 1607, 3548, 567, 567, 1604, 3562, 2296, 2296, 3563, - 3566, 3569, 3693, 3572, 3578, 3570, 3595, 3584, 536, 536, - 3597, 536, 3607, 3362, 3611, 536, 3613, 3614, 536, 3617, - 3623, 3630, 3631, 3635, 3640, 3632, 822, 822, 3642, -2183, - 3644, 3306, 3647, 3813, 3653, 3651, 1705, 1706, 1707, 1708, - 1709, 1710, 3648, 3652, 3660, 536, 3658, 3662, 3089, 3663, - 3666, 3671, 869, 3682, 3676, 3683, 3684, 1054, 3689, 917, - 869, 567, 869, 869, 869, 536, 3690, 3691, 3709, 1404, - 536, 536, 3728, 2787, 1259, 536, 1607, 3699, 3701, 1404, - 536, 887, 1404, 536, 536, 3731, 3703, 3733, 536, 1337, - 3749, 3752, 536, 3762, 3753, 3729, 536, 3730, 3786, 1676, - 3776, 1604, 1677, 3781, 3790, -1919, 1678, 1679, 536, 3788, - 3795, 1682, 1683, 1684, 3800, 79, 2108, 2112, 3812, 3807, - 2110, 3811, 1256, 2111, 2114, 1260, 934, 3814, 2115, 534, - 1202, 3096, 2822, 2766, 2366, 2776, 1261, 3100, 1687, 3591, - 3028, 1256, 1257, 3697, 3657, 1688, 3787, 3409, 1262, 2511, - 1178, 3376, 2879, 832, 536, 1604, 3680, 3769, 3511, 3727, - 3734, 1257, 536, 3763, 3546, 825, 1822, 1604, 2756, 2783, - 2336, 2337, 1689, 3199, 3725, 3732, 3065, 1596, 3152, 3723, - 1263, 536, 2752, 1945, 3722, 3793, 1079, 3495, 1258, 1991, - 1607, 2871, 2826, 1992, 1993, 2873, 1905, 1604, 1994, 1995, - 1996, 3213, 2739, 3177, 1604, 1494, -1919, 1258, 3087, 3154, - 1495, 1742, 2725, 2316, 3357, 2977, 1785, 2906, 3088, 3702, - 2735, 1524, 1784, 3643, 2284, 3149, 3568, 2315, 826, 2601, - 834, 1789, 2710, 3461, 1461, 1265, 2882, 3262, 2883, 2900, - 2899, 3517, 2888, 2932, 2891, 1445, 3646, 2615, 1604, 3645, - 2661, 1447, 1604, 1451, -1919, 1452, 1453, 1454, 1604, 1455, - 1266, 1456, 2956, 1457, 2685, 2728, 2631, 3484, 2683, -1919, - 1690, 732, 2974, 3316, -1919, 1596, 2662, 2041, 3089, -1919, - 2412, 1268, 1604, 3633, 732, 1259, 3315, 1691, -1919, 3286, - 1006, 1607, 1692, -1919, 2608, 2253, 2840, 1607, 1406, 3413, - 1957, 887, 3029, 552, 1259, 2255, 1496, 536, 536, 2840, - 536, 2619, 2881, 2393, 0, 1693, 1694, 0, 0, 536, - 1607, 1234, 0, 0, 0, -1919, 0, 0, -1414, 0, - 0, 1695, 0, 0, 0, 536, 1260, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -1919, 1261, 0, 0, - 0, 0, 0, 0, 0, 1260, 0, 0, 0, 1262, - 0, 0, 0, 0, 1607, 0, 1261, 553, 0, 1079, - 536, 1696, 1991, 0, 1697, 73, 1992, 1993, 1262, 0, - 3090, 1994, 1995, 1996, 0, 0, 536, 536, 1698, 0, - 536, 1263, 536, 0, 0, 73, 0, -1919, 824, 0, - -1919, 0, 1998, 0, 0, 0, -1919, 0, 0, 0, - 1263, 0, 73, 0, 0, 0, 0, 1596, 0, 0, - 0, 886, 0, 554, 536, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1676, 0, 0, 1677, 0, 0, - 0, 1678, 1679, 555, 0, 0, 1265, -1919, 536, 0, - 0, 0, 824, 824, 903, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1265, 0, 0, 0, 0, - 2702, 1266, -1919, 1687, 0, 1999, 0, 3149, 73, 1676, - -2183, 0, 1677, 1966, 0, 0, 1678, 1679, 0, 0, - 1266, 1700, 1268, 0, 0, 0, 0, 0, 0, 0, - 869, 732, 556, 2731, 2731, 869, 3142, 1689, 3529, -224, - 0, 1268, 3514, 3091, 0, 567, 3092, 0, 1687, 0, - 0, 0, 0, 1596, 0, -2183, 2840, 536, 0, 0, - 1967, 0, 874, 3521, 3522, 0, 536, 0, 536, 0, - 536, 0, 0, 2822, 536, 0, 536, 0, 536, 0, - 0, 1968, 1689, 0, 0, 557, 0, 558, 3535, 0, - 534, -1919, 536, 0, 0, 0, 2451, 536, 536, 1969, - 0, 0, -1919, 2669, 1970, 0, 0, 1596, 3205, 536, - 559, 0, 0, 560, 832, 1998, 0, 23, 0, 1596, - 0, 3588, -1919, 3590, -1919, -1919, 732, 1971, 0, 0, - 1972, 536, 0, 1701, 0, -2183, 1702, 1703, 1704, 0, - 1705, 1706, 1707, 1708, 1709, 1710, 1973, 1604, 2679, 1596, - 0, 3600, -2183, 0, 0, 0, 1596, -2183, 1833, 0, - 0, -1919, 0, 0, -1919, -1919, -1919, 3626, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 536, - -2183, 0, 0, 0, 3629, 0, 0, 0, 1999, 536, - 0, 834, 0, 0, 0, 0, -2183, -2183, 0, 0, - 1596, 536, -2183, 1604, 1596, 0, 0, 0, 0, 0, - 1596, 0, 0, 0, 0, 0, 536, 0, 536, 0, - 0, 0, 0, 2000, 2001, 2002, 0, 2003, 2004, 2005, - 2006, 2007, 2008, 0, 1596, 0, 0, 536, 981, 567, - 567, -2183, 1974, 0, 0, 0, 0, 0, 0, 534, - 1975, 0, 0, 1698, 3312, 0, 0, 0, 0, 0, - 0, 536, 0, 0, 26, 27, 28, 0, 0, 0, - 0, 0, 1976, 832, 0, 0, 536, 0, 0, 0, - 0, 0, 1004, 543, 0, 0, 0, 0, 532, 3149, - 869, 732, 0, 0, 534, 0, 0, 0, 1698, 822, - 0, 0, 1977, 1031, 1031, 0, 822, 0, 0, 1031, - 1058, 0, 0, 0, 536, 0, 3600, 3735, 832, 1604, - 0, 0, 849, 849, 849, 0, 0, 849, 536, 536, - 536, 33, 0, 0, 3710, 1128, 1128, 849, 849, 536, - 849, 0, 849, 3750, 0, 0, 0, 534, 0, 0, - 834, 0, 0, 0, 869, 0, -2183, 0, 0, 0, - 567, 0, 0, 0, 536, 0, 0, 0, 2941, 2942, - 38, 832, 0, 869, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1604, 0, 0, 869, 837, 0, - 0, 0, 0, 0, 0, 834, 0, 0, 0, 0, - 0, -2183, 0, 0, 0, 40, 2000, 2001, 2002, 0, - 2003, 2004, 2005, 2006, 2007, 2008, 43, 0, 0, 3412, - 0, 0, 0, 536, 0, 0, 869, 1342, 0, 0, - 536, 0, 0, 44, 0, 0, 0, 1352, 0, 0, - 23, 869, 869, 869, 869, 869, 0, 0, 834, 0, - 23, 0, 0, 0, 0, 73, 0, 45, 1375, 735, - 0, 0, 0, 0, 0, 0, 0, 0, -2183, 0, - 0, 46, 0, 0, 0, 1705, 1706, 1707, 1708, 1709, - 1710, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1031, 1058, 0, 869, 0, 1604, 1468, 0, 0, 0, - 0, 0, 1031, 1031, 0, 0, 0, 0, 0, 567, - 0, 0, 0, -2183, 0, 822, 736, 822, 0, 0, - 1705, 1706, 1707, 1708, 1709, 1710, 822, 1676, 0, 0, - 1677, 0, 737, 0, 1678, 1679, 567, 0, 1604, 0, - 1404, 0, 0, 0, 0, 0, 0, 1676, 0, 0, - 1677, 0, 0, 1611, 1678, 1679, 0, 3482, 0, 1682, - 1683, 1684, 0, 0, 0, 0, 1687, 0, 0, 1596, - 0, 0, 0, -2183, 0, 0, 1685, 0, 1598, 0, - 0, 567, 738, 1599, 0, 3589, 1687, 26, 27, 28, - 0, 0, 739, 1688, 0, 0, 0, 26, 27, 28, - 1689, 0, 0, 0, 1604, 740, 567, 0, 0, 0, - 741, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1689, 0, 0, 0, 0, 1596, 0, 0, 0, 0, - 0, 3142, 0, 0, 0, 0, 0, 0, 1676, 742, - 0, 1677, 0, 0, 0, 1678, 1679, 0, 0, 0, - -2183, -2183, -2183, 0, 33, 0, 0, 0, 0, 1736, - 0, 0, 0, 0, 33, 0, 2987, 0, 0, 0, - 0, 3549, 73, 886, 0, 567, 567, 1687, 0, 0, - 0, 0, 869, 743, 1688, 869, 3269, 0, 744, 1604, - 0, 0, 0, 38, 0, 0, 0, 0, -2183, 0, - 0, 0, 0, 38, 0, 0, 1468, 1128, 1128, 0, - 0, 1689, 0, 0, 1011, -2183, 869, 0, 1690, 1809, - -2183, 869, 1821, 0, 0, 1023, 0, 0, 40, 0, - 0, 0, 1039, 0, 869, 1691, 0, 0, 40, 43, - 1692, 1596, 0, 0, 0, 0, 0, 0, 0, 43, - 0, 869, 0, 0, 555, 869, 44, 0, 0, -2183, - 745, 1873, 0, 1693, 1694, 1601, 44, 0, 1598, 0, - 0, 0, 3619, 1599, 0, 746, 0, 903, 0, 1695, - 45, 0, 0, 0, 0, 14, 15, 0, 0, 0, - 45, 0, 0, 0, 46, 73, 0, 0, 0, 0, - 0, 0, 0, 1604, 46, 0, 1596, 0, 0, 1690, - 747, 0, 0, 748, 0, 0, 1698, 0, 0, 1696, - 0, 0, 1697, 1893, 749, 869, 1691, 750, 0, 0, - 0, 1692, 23, 869, 0, 0, 1698, 1404, 1604, 1699, - 0, 0, 1404, 0, 0, 0, 1938, 751, 0, 0, - 0, 0, 0, 0, 0, 981, 0, 0, 0, 0, - 981, 752, 567, 567, 0, 567, 981, 0, 753, 754, - 1695, 0, 0, 0, 0, 0, 0, 0, 0, 755, - 0, 0, 0, 0, 0, 756, 0, 0, 0, 0, - 0, 1959, 1961, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1604, 0, 0, 0, 73, 0, - 1604, 0, 0, 3142, 757, 0, 0, 1596, 0, -2183, - 0, 0, 0, 0, 0, 0, 0, 1698, 0, 0, - 0, 0, 0, 1604, 0, 0, 0, 0, 0, 1700, - 0, 824, 0, 1023, 0, 1468, 1468, 0, 0, 0, - 0, 1468, 824, 532, 0, 1601, 0, 0, 0, 0, - 1596, 0, 0, 0, 0, 0, 1031, 0, 567, 2034, - 0, 0, 0, 1128, 1128, 0, 869, 1604, 0, 26, - 27, 28, 0, 822, 1042, 822, 0, 1614, 822, 1043, - 0, 0, 0, 822, 0, 1128, 822, 0, 822, 1626, - 0, 0, 822, 0, 567, 0, 567, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1596, 0, 1655, 0, - 1700, -2183, 0, 0, 0, 0, 0, 0, 1705, 1706, - 1707, 1708, 1709, 1710, 0, 0, 33, 0, 1044, 0, - 0, 1701, 0, 0, 1702, 1703, 1704, 35, 1705, 1706, - 1707, 1708, 1709, 1710, 1676, 0, 0, 1677, 0, 0, - 0, 1678, 1679, 0, 0, 0, 0, 0, 0, 0, - 0, 37, 0, 0, 0, 38, 0, 0, 0, 0, - 1604, 1598, 0, 0, 0, 0, 1599, 1676, 0, 0, - 1677, 0, 0, 1687, 1678, 1679, 0, 0, 0, 0, - -2183, 1596, 0, 0, 0, 2148, 903, 903, 0, 903, - 40, 1045, 0, 0, 0, 1959, 1961, 0, 567, 1226, - 0, 43, 0, 0, 0, 1404, 1687, 1689, 0, 0, - 0, 0, 1701, -2183, 0, -2183, -2183, -2183, 44, 1705, - 1706, 1707, 1708, 1709, 1710, 0, 0, 1046, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1602, 981, 0, - 1689, 1468, 45, 1047, 1042, 0, 0, 0, 0, 1043, - 0, 0, 0, 0, 1048, 0, 46, 0, 0, 1598, - 0, 0, 0, 0, 1599, 0, 0, 0, 0, 1128, - 0, 0, 0, 2990, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2251, 0, 869, 0, 869, 0, - 1049, 0, 0, 0, 0, 1596, 0, 0, 0, 869, - 0, 0, 2267, 0, 0, -2183, 2991, 0, 1044, 0, - 0, 1227, 1079, 0, 1468, 1991, 0, 0, 0, 1992, - 1993, 0, -2183, 0, 1994, 1995, 1996, -2183, 0, 0, - 1596, 0, 0, 0, 0, 0, 0, 1050, -2183, 869, - 0, 567, 0, 0, 1051, 0, 0, 0, 1601, 0, - 0, 0, 0, 2318, 2320, -2183, 0, 0, 1603, 2323, - -2183, 0, 1821, 567, 0, 0, -2183, 0, 73, 0, - 0, 0, 0, 0, 567, 2344, 567, 1821, 0, 567, - 0, 1045, 0, 0, 0, 0, 1052, 0, 0, 567, - 0, 567, 0, 0, 0, 0, 1596, 0, 0, -2183, - 0, 1598, 1596, 981, 567, 1053, 1599, 0, 981, 567, - 0, 0, 0, 567, 567, 1821, 567, 1046, 567, 567, - 0, 0, 0, 1698, 0, 1596, 0, 1602, 0, 0, - 868, 0, 0, 1047, 876, 0, 0, 0, 0, 0, - 2413, 0, 1604, 0, 1048, 0, 1601, 0, 1352, 0, - 869, 869, 869, 869, 869, 869, 1698, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1596, - 2441, 0, 0, 0, 0, 0, 0, 0, 1054, 824, - 1049, 824, 0, 1228, 824, 0, 0, 1404, 0, 824, - 0, 2504, 824, 0, 824, 0, 914, 0, 824, 0, - 0, 2059, 0, 0, 919, 0, 922, 1598, 926, 0, - 0, 0, 1599, 0, 0, 1470, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -2183, 1050, -2183, 0, - 0, 0, 0, 0, 1051, 0, 0, 0, 0, 0, - 0, 1468, 1468, 1468, 1468, 1468, 1468, 0, 1603, 1468, - 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, -2183, - 0, 1598, 0, 0, 0, 0, 1599, 0, 0, 0, - 0, 0, 0, 1598, 0, 0, 1052, 0, 1599, 567, - 0, 0, 1596, 0, 73, 0, 0, 0, 1601, 0, - 0, 0, 0, 869, 0, 1053, 0, 0, 0, 0, - 0, 1999, 0, 1598, 0, 0, 822, 0, 1599, 0, - 1598, 0, 822, 0, 0, 1599, 0, 0, 567, 0, - 0, 0, 0, 0, 567, 0, 0, 0, 0, 0, - 0, 0, 0, 2613, 2613, 0, 0, 0, -2183, 0, - 0, 0, 0, 0, 0, 1705, 1706, 1707, 1708, 1709, - 1710, 0, 0, 0, 1598, 568, 0, 0, 1598, 1599, - 0, 568, 0, 1599, 1598, 823, 0, 2199, 1054, 1599, - 0, -2183, 568, 2060, 0, 0, 0, 0, 1705, 1706, - 1707, 1708, 1709, 1710, 0, 0, 568, 568, 1598, 0, - 0, 0, 0, 1599, 1601, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 567, 0, - 0, 0, 0, 567, 0, 0, 1781, 0, 567, 823, - 823, 0, 0, 0, 0, 1470, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, - 0, 0, 1468, 1468, 0, 0, 0, 0, 1601, 0, - 1602, 0, 0, 0, 568, 0, 0, 0, 0, 0, - 1601, 2148, 0, 0, 0, 0, 0, 1468, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1601, 0, 0, 0, 822, 0, 0, 1601, 0, 0, - 0, 0, 0, 0, 0, 0, 567, 0, 0, 0, - 822, 0, 0, 0, 822, 2267, 0, 0, 0, 2000, + 2953, 2955, 1331, 536, 536, 536, 3733, 836, 536, 3658, + 2191, 1246, 536, 1074, 1836, 536, 536, 536, 536, 536, + 536, 536, 536, 536, 3797, 1075, 536, 3658, 1867, 825, + 1212, 825, 1214, 536, 825, 1337, 2954, 2956, 2957, 825, + 3832, 1246, 825, 3455, 825, 1604, -2173, -2173, 825, 3528, + 2281, 1505, 1173, 536, 1189, 1837, 1196, 534, -2174, -2174, + 1197, 3549, 1199, 905, -2175, -2175, -2176, -2176, -2177, -2177, + 1203, 2326, 1200, 2730, 1201, 1248, 2885, 1870, 536, 1835, + -2178, -2178, -2180, -2180, 2946, 1204, 2948, 2949, 2246, 536, + 536, -2181, -2181, -2182, -2182, 1206, 884, 1186, 1213, 1835, + 1835, 2382, -2183, -2183, 1837, 1248, 1232, 1249, 1235, 1838, + -2184, -2184, 1237, -2193, -2193, -2193, 3550, 2003, 2004, 2005, + 2006, 2007, 2008, 895, 1238, 3551, 2175, -2185, -2185, 14, + 15, 1246, 1607, -2187, -2187, -2189, -2189, 2383, -666, -2192, + -2192, 1240, 732, -666, 1887, 1888, 732, 1836, 1239, 3552, + 2300, 2301, 1730, 2356, -722, -722, 1241, 2363, 1838, 1989, + 1990, -726, -726, -725, -725, 2010, 1242, 1836, 1836, 1434, + 1435, 3100, 1438, 1439, 3179, 3180, 23, 1833, 3305, 3306, + 3783, 3786, 1250, 2877, 2879, 3772, 3773, 732, 1045, 1254, + 536, 2389, 3809, 3810, 896, 1248, 1255, 1337, 1963, 116, + 536, 536, 2749, 2750, 1733, 1734, 1272, 1282, 1596, 1340, + 2800, 1276, 1250, 1280, 1343, -666, 3049, 1344, 1354, 1598, + 1349, 1369, 1366, 3553, 1046, 1368, 1833, 2390, 1376, 1383, + 2804, 2808, 1377, 1386, 1387, 1604, 3554, 1837, 1607, 1392, + 1514, 1410, 2499, 3112, 2453, 1411, 3143, 3027, 3130, 1416, + 3173, 1048, 1474, 1490, 1487, 1501, 1489, 1837, 1837, 2498, + 732, 1497, 3269, 1509, 1510, 1516, -666, 1337, 536, 1527, + 1517, 1523, 1529, 1609, 1610, 897, 536, 3188, 1612, 1470, + 1470, -907, -914, 1621, 1950, 1625, 1951, 2083, 3576, 46, + -747, 1838, 1607, -748, -904, -905, 536, 536, 1636, 536, + -908, 1637, 1250, 23, 1607, 536, 536, 536, 536, 536, + 536, 1838, 1838, 536, 536, 536, 536, 536, 536, 536, + 536, 536, 536, 26, 27, 28, 3763, -906, 536, 536, + 3765, 1644, 536, 1659, 1607, 1669, 2135, 1671, 937, 536, + 1716, 1607, 1720, 2136, 2137, 1732, 1740, 1718, 2138, 2139, + 2140, 1741, 1745, 1753, 1216, 1750, 1218, 1788, 1790, 1833, + 1792, 1810, 1808, 536, 938, 1829, 1830, 1840, 1841, 3073, + 536, 1842, 536, 1847, 1854, 3074, 536, 1855, 1859, 1833, + 1833, 1869, 1877, 1052, 1874, 1607, 2594, 3528, 3075, 1607, + 33, 536, 2597, 1337, 1890, 1607, 1891, 1892, 1596, 1896, + 1899, 35, 1507, 1906, 1907, 1599, 3234, 3235, 3825, 1598, + 1913, 2730, 3076, 1914, 3077, 1917, 1920, 1921, 1923, 1924, + 1925, 1607, 534, 1926, 1928, 37, 1929, 1943, 534, 38, + 898, 939, 1942, 536, 536, 1947, 1955, 1980, 3028, 1982, + 536, 3536, 1983, 3555, 2019, 1985, 3556, 1988, 2011, 3337, + 26, 27, 28, 2020, 2027, 1005, 2030, 2053, 2050, 2052, + 940, 832, 2057, 2063, 40, 2067, 2068, 832, 2078, 1615, + 2069, 2075, 2090, 536, 2081, 43, 1622, 536, 1627, 2082, + 2085, 2086, 536, 536, 887, 2121, 1080, 1063, 2120, 1677, + 2160, 2167, 44, 2169, 1470, 2164, 2155, 3346, 3347, 3576, + 2156, 3232, 2170, 3078, 941, 2171, 2172, 2213, 536, 536, + 2193, 2214, 1171, 536, 834, 2240, 45, 33, 2241, 2247, + 834, 3221, 2216, 2259, 2260, 23, 2261, 2262, 2263, 536, + 46, 2039, 536, 536, 536, 896, 2277, 2267, 1243, 1657, + 2280, 2290, 2291, 2289, 1244, 2292, 2293, 2294, 3576, 2311, + 536, 732, 1256, 2315, 2319, 2316, 38, 536, 1604, 1404, + 536, 838, 2324, 2332, 1404, 2328, -591, 2333, 2334, 2360, + 2361, 2342, 1257, 3252, 3079, 2366, 536, 2367, 2403, 3080, + 536, -591, 825, 897, 2417, 534, -591, 3592, 825, 2404, + 536, 40, 2405, 2427, 2421, 1599, 2719, 2437, 2438, 2441, + 2442, 2439, 43, 3576, 2084, 2440, 2454, 536, 536, 2458, + 2461, 2459, 534, 2500, 2502, 2501, 2503, 2506, 1258, 44, + 2504, 2510, 2519, 2527, 536, 2729, 536, 2016, 534, 3081, + 1991, 2557, 534, 2015, 942, 2564, 2574, -591, 2565, 2566, + 3323, 536, 2586, 45, 2570, 943, 2575, 3082, 2598, 1245, + 2610, 832, 1401, 2596, 2618, 732, 1604, 3029, -591, 2619, + 3605, 2613, 1444, 2620, 732, 732, 732, 832, 2621, 2623, + 1470, 832, 26, 27, 28, 2356, 2356, 2356, 2624, 2625, + 2629, 2626, 944, 2630, 2637, 2536, 2537, 2538, 2539, 2540, + 2541, 2638, 2641, 2545, 2546, 2547, 2548, 2549, 2550, 2551, + 2552, 2553, 2554, 2643, 834, 2642, 945, 2646, 2647, -591, + 536, -591, 2644, 3478, 2331, 1259, 2645, 2659, -591, 1337, + 834, 1596, 2648, 2649, 834, 2345, -591, 2348, 2655, 1649, + 2359, -591, 1598, 2666, 2667, 946, 2669, 2681, 2674, 33, + 2368, 2691, 2370, 2696, 2690, 2697, 2698, 2709, 2714, 2716, + 2717, 3083, 732, 2723, 2725, 2377, 2726, 1607, 1862, -728, + 2380, 3084, 1908, 2844, 2385, 2386, 1260, 2388, 1909, 2392, + 2393, 2736, 825, 2737, 1911, 1912, 2740, 1261, 38, 2739, + 2452, 2743, -591, 2747, 1670, 1470, 1805, 2748, 825, 1262, + 2751, 1966, 825, 2754, 1673, 2752, 2757, 2760, 1604, 2756, + 2781, 23, 2783, -591, 2799, 2792, 2805, 1959, 1961, 2797, + 1246, 1607, 2798, 40, 1404, 536, 1723, 2835, 2806, 1596, + 2807, 1263, 2819, 2836, 43, 1728, 2820, 3560, 3561, 2841, + 1598, 732, 2863, 2834, 2870, 2854, 2882, 1668, 1967, 2866, + 2855, 44, 1963, 2141, 2142, 2143, 1833, 2144, 2145, 2146, + 2147, 2148, 2149, 3581, -591, 3583, 2889, 2175, 2897, 1968, + 2900, 2920, 2921, -591, 2907, 45, 2903, 2923, 2906, 536, + 1264, 2934, 2908, -591, 1248, 2909, 1265, 1969, 2924, 46, + 2935, 2950, 1970, 2940, 2961, 2941, 2968, 2989, 2670, 2671, + 3591, 2958, 3002, 3008, 2969, 3019, 2987, 2990, 3022, 3042, + 2993, 1266, 3003, 3046, 1604, 1971, 1267, 3010, 1972, 3055, + 3014, 536, 3020, 3040, 3061, 3044, 3062, 3068, 1599, 3088, + 3104, 534, 1268, 3127, 1973, 3128, 3129, 3593, 1607, 3595, + 3133, 1180, 3137, 1872, 3138, 3153, 3154, 3159, 3160, 3164, + 887, 3169, 3163, 932, 3181, 3182, 536, 933, 26, 27, + 28, 3186, 2420, 536, 536, 3191, 3192, 3224, 1604, 1256, + 832, 1596, 3197, 3217, 3220, 3228, 3239, 3240, 3241, 536, + 1604, 3284, 1598, 3245, 3244, 887, 3005, 3270, 3277, 1257, + 3280, 1250, 536, 3291, 3298, 536, 3281, 536, 1959, 1961, + 3293, 3302, 3312, 3316, 1607, 536, 3685, 3320, 536, 536, + 1604, 3303, 3304, 536, 536, 3726, 3321, 1604, 3330, 3310, + 536, 3590, 3333, 834, 3311, 33, 1599, 3322, -591, 3335, + 1974, 3336, 3340, 3348, 3689, 1258, 3094, 536, 1975, 3048, + 3349, 3674, 3353, 3351, 3352, 3354, 3095, 3368, 536, 3031, + 3370, 3356, 3383, 3357, 3385, 3390, 3395, 3366, 3371, 3372, + 1976, 1604, 3381, 3382, 38, 1604, 3387, 3394, 536, 3403, + 3388, 1604, 1962, 3398, 3404, 3669, 3407, 1596, 3409, 3411, + 3415, 3417, 3418, 3421, 3422, 3423, 3426, 3427, 1598, 3430, + 1977, 3431, 3434, 3450, 3452, 3451, 3456, 1604, 932, 40, + 3463, 1199, 933, 3468, 3480, 3466, 3096, 3481, 3535, 3537, + 43, 3543, 732, 3545, 3546, 536, 536, 732, 3566, 732, + 536, 536, 3578, 2356, 3579, 3585, 1079, 44, 3110, 1991, + 2363, 1596, 1259, 1992, 1993, 536, 536, 3582, 1994, 1995, + 1996, 3588, 1598, 1596, 3586, 3594, 3600, 3611, 536, 3613, + 3329, 45, 3627, 3623, 1598, 3629, 3630, -2158, -2159, 1607, + 887, 3645, 1404, -2160, -2161, 46, 3140, 536, 1599, 1950, + 3647, -2162, -2163, 1596, 3184, -2164, -2165, -2166, -2167, -2168, + 1596, 3639, 3648, 1260, 1598, -2169, 3650, 1908, 3651, 3652, + -2171, 1598, 1256, 1909, 1261, -2172, 2499, -2173, -2174, 1911, + 1912, 3174, -2175, -2176, 3655, -2177, 1262, -2178, 3097, -2180, + -2181, -2182, 1257, -2183, 3660, -2184, -2185, -2186, -2187, 3273, + -2188, 887, 3646, 536, 1596, -2189, 1607, -2190, 1596, -2191, + 3662, 3715, -2192, 3376, 1596, 1598, -1377, 3664, 1263, 1598, + 3668, 3667, 3671, 536, 536, 1598, 536, 3672, 3673, 3678, + 536, 3680, 3682, 536, 23, 3683, 3686, 3691, 1258, 3696, + 1596, 532, 543, 3704, 3706, 3711, 3712, 567, 3713, 3731, + 3721, 1598, 3723, 567, 1599, 3750, 3753, 822, 3725, 837, + 3755, 3758, 536, 840, 567, 849, 3774, 3777, 849, 3839, + 3778, 869, 869, 1265, 3787, 869, 3751, 3752, 567, 567, + 3795, 3802, 536, 23, 3807, 3812, 3814, 536, 536, 3816, + 3821, 3826, 536, 1607, 3837, 3833, 3838, 536, 1266, 1997, + 536, 536, 3840, 887, 1202, 536, 1337, 3103, 1599, 536, + 2769, 822, 822, 536, 2779, 2369, 3107, 3607, 3719, 1268, + 1599, 3098, 1998, 3035, 3099, 536, 3677, 3813, 3373, 1496, + 2512, 2114, 3343, 2884, 3746, 1259, 3700, 869, 79, 1178, + 3794, 2110, 2862, 2117, 917, 869, 567, 869, 869, 869, + 1599, 3476, 2112, 934, 2113, 2116, 1042, 1599, 3749, 3788, + 3756, 1043, 3558, 2759, 2786, 534, 2338, 2339, 2995, 2996, + 3747, 536, 2252, 1822, 3754, 3072, 3111, 1676, 3158, 536, + 1677, 26, 27, 28, 1678, 1679, 1260, 2755, 3745, 1945, + 3744, 3819, 3460, 2876, 1905, 1999, 2878, 1261, 536, 3178, + 2830, 1599, 2742, 3136, 832, 1599, 1742, 1607, 1494, 1262, + 3113, 1599, 2728, 1604, 2318, 1495, 1687, 1785, 2911, 3724, + 1044, 1784, 1524, -2193, 2738, 2286, 3663, 3584, 2317, 1789, + 26, 27, 28, 826, 2713, 3227, 1833, 1599, 2602, 3425, + 732, 1263, 2905, 2904, 2937, 3482, 2321, 2323, 33, 1461, + 1689, 2844, 2617, 732, 3666, 3665, 2664, 834, 1445, 2963, + 1607, 1447, 1451, 2731, 2844, 3377, 1452, 1604, 3449, 2688, + 1453, 1454, 1607, 2686, 2041, 2362, 1455, 2634, 2665, 2981, + 3653, 887, 536, 536, 3253, 536, 3283, 38, 1456, 1006, + 1457, 3282, 1256, 1045, 536, 1607, 1265, 33, 2415, 2609, + 73, 1957, 2255, 1234, 3036, 2886, 2257, 2396, 0, 1406, + 536, 0, 1257, 2394, 0, 0, 2672, 0, 0, 0, + 73, 1266, 40, 824, 0, 825, 0, 0, 0, 1046, + 0, 2412, 2412, 43, 0, 0, 38, 73, 14, 15, + 1607, 0, 1268, 0, 0, 1047, 886, 536, -2193, 0, + 44, 0, 0, 0, 0, 0, 1048, 0, 1258, 0, + 0, 0, 0, 536, 536, -2193, 0, 536, 1042, 536, + -2193, 40, 0, 1043, 45, 0, 1596, 824, 824, 903, + 0, 0, 43, 3190, 1604, 23, 0, 1598, 46, 0, + 0, 0, 1049, 0, 0, 0, 0, 0, 0, 44, + 0, 536, 0, 73, 0, 0, 0, 0, 0, -2193, + 0, 2521, 0, 2000, 2001, 2002, 0, 2003, 2004, 2005, + 2006, 2007, 2008, 45, 0, 536, 0, 0, 0, 3096, + 1596, 0, 1044, 0, 0, 0, 0, 46, 3051, 1050, + 0, 1598, 3053, 0, 0, -1912, 1051, 0, 0, 0, + 1604, 3531, 0, 0, 0, 1259, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1698, 0, 0, 0, + 0, 3105, 0, 0, 0, 732, 0, 0, 0, 3541, + 0, 0, 0, 0, 536, 536, 2844, 0, 1052, 3114, + 3115, 3116, 3117, 0, 3119, 3120, 3121, 3122, 3123, 0, + 0, 536, 0, 0, 0, 1045, 1260, 1053, 0, 0, + 536, 0, 536, 1226, 536, 0, 0, 1261, 536, 0, + 536, 0, 536, 0, 0, 0, 0, 0, 0, 1262, + 0, 0, 26, 27, 28, 0, 0, 536, 0, 0, + 0, 1046, 536, 536, 0, 0, -1912, 1596, 0, 0, + 0, 0, 0, 534, 536, 0, 0, 1047, 1598, 3325, + 0, 1263, 0, 3604, 0, 3606, 0, 0, 1048, -2193, + 0, 732, 0, 1599, 0, 0, 536, 0, 0, 0, + 1054, 0, 3616, 0, 0, 869, 0, 0, 0, 0, + 869, 0, 832, 0, -1912, 0, 0, 0, 0, 33, + 567, 0, 0, 0, 1049, 1604, 0, 0, 0, -1912, + 35, 0, 0, 1596, -1912, 0, 1265, 3531, 0, -1912, + 0, 0, 0, 0, 1598, 1227, 0, 1599, -1912, 0, + 0, 0, 0, -1912, 37, 0, 0, 0, 38, 0, + 0, 1266, 0, 0, 0, 834, 0, 0, 0, 0, + 0, 1050, 0, 0, 0, 0, 3642, 0, 1051, 0, + 0, 0, 1268, 0, 0, -1912, 0, 0, 0, 0, + 0, 0, 1604, 40, 3399, 536, 0, 3649, 0, 0, + 0, -2193, 0, 0, 43, 536, -1912, 0, 1705, 1706, + 1707, 1708, 1709, 1710, 0, 1079, 0, 536, 1991, 0, + 1052, 44, 1992, 1993, 0, 0, 0, 1994, 1995, 1996, + 0, 0, 536, 0, 536, 0, 0, 0, 0, 1053, + 0, 0, 0, 1601, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 536, 0, 0, 0, -1912, 0, 46, + -1912, 0, 1079, 0, 1599, 1991, -1912, 0, 0, 1992, + 1993, 0, 0, 0, 1994, 1995, 1996, 0, 0, 1604, + 552, 536, 0, 0, 534, 3324, 0, 0, 1596, 0, + 0, 2984, 0, 0, 0, 0, 536, 0, 0, 1598, + 0, 0, 0, 0, 0, -1424, 0, -1912, 0, 3531, + 0, 732, 1054, 981, 567, 567, 0, 1228, 0, 0, + 2790, 0, 3616, 832, 0, 0, 0, 0, 0, 0, + 1599, 0, -1912, 534, 0, 3759, 536, 0, 0, 0, + 0, 0, 0, 0, 553, 0, 0, 0, 0, 0, + 536, 536, 536, 0, 0, 1596, 0, 1004, 543, 0, + 0, 536, 3775, 532, 0, 869, 1598, 0, 0, 0, + 73, 0, 832, 0, 822, 0, 834, 0, 1031, 1031, + 2826, 822, 0, 0, 1031, 1058, 0, 0, 534, 536, + 0, 0, 874, 1604, 0, 0, 0, 849, 849, 849, + 554, 0, 849, 0, 0, 0, 0, 0, 2314, 0, + 1128, 1128, 849, 849, 0, 849, 0, 849, 0, 0, + 555, -1912, 0, 0, 0, 834, 0, 832, 0, 869, + 0, 1998, -1912, 1601, 0, 567, 0, 0, 0, 0, + 0, 0, 1596, 0, 0, 0, 1604, 0, 869, 536, + 0, 0, -1912, 1598, -1912, -1912, 536, 0, 1604, 0, + 0, 0, 869, 837, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1998, 556, + 834, 1604, 2887, 0, 2888, 1599, -224, 0, 2893, 0, + 2896, -1912, 0, 0, -1912, -1912, -1912, 0, 0, 0, + 0, 869, 1342, 0, 1999, 0, 0, 0, 0, 0, + 0, 0, 1352, 0, 0, 0, 869, 869, 869, 869, + 869, 0, 0, 0, -1914, 0, 1604, 0, 0, 0, + 0, 0, 557, 1375, 558, 0, 0, 0, 0, 0, + 0, 0, 0, 3479, 0, 0, 0, 0, 0, 0, + 0, 1999, 1599, 0, 0, 0, 1596, 559, 0, 0, + 560, 3533, 3534, 0, 0, 1031, 1058, 1598, 869, 0, + 0, 1468, 0, 0, 0, 0, 0, 1031, 1031, 0, + 0, 0, 0, 0, 567, 0, 3547, 73, 886, 0, + 822, 0, 822, 0, 0, 1042, 0, 0, 0, 0, + 1043, 822, 0, 0, 0, 0, 0, 0, 0, 1596, + 0, 567, 0, 0, 0, 0, 0, 0, 0, 0, + 1598, 1596, 0, 0, 0, -1914, 0, 0, 1611, 1011, + 0, 0, 1598, 0, 0, 0, 0, 1604, 0, 1599, + 1023, 0, 0, 0, 1596, 0, 0, 1039, 0, 0, + 0, 0, 0, 0, 0, 1598, 567, 0, 1602, 1044, + 0, 0, 0, -1929, 0, 0, 0, 0, 0, 0, + 0, 0, 1603, -1914, 0, 0, 0, 0, 0, 0, + 0, 567, 0, 0, 0, 0, 0, 0, -1914, 1596, + 0, 0, 903, -1914, 0, 0, 0, 0, -1914, 0, + 1598, 0, 0, 0, 0, 0, 0, -1914, 0, 0, + 73, 0, -1914, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2000, 2001, 2002, 0, 2003, 2004, 2005, 2006, + 2007, 2008, 1045, 0, 1736, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -1914, 0, 0, 0, 0, 0, + 567, 567, 0, 1599, 0, 0, 1601, 869, 2362, 0, + 869, 0, 0, 0, -1929, -1914, 0, 0, 1046, 2000, 2001, 2002, 0, 2003, 2004, 2005, 2006, 2007, 2008, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1601, 0, 0, 0, 1601, 0, 0, 1602, 0, - 0, 1601, 0, 0, 0, 567, 0, 0, 1468, 0, - 1128, 567, 0, 0, 1596, 0, 0, 0, 0, 0, - 0, 1603, 0, 0, 0, 1601, 0, 1079, 0, 0, - 1991, 0, 0, 1893, 1992, 1993, 0, 0, 0, 1994, - 1995, 1996, 0, 0, 0, 0, 0, 1079, 73, 0, - 1991, 0, 0, 0, 1992, 1993, 2978, 0, 0, 1994, - 1995, 1996, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3293, 1079, 0, 0, - 1991, 0, 0, 0, 1992, 1993, 0, 0, 0, 1994, - 1995, 1996, 0, 0, 950, 0, 0, 0, 0, 957, - 0, 0, 0, 0, 0, 0, 3294, 0, 0, 0, - 0, 0, 0, 0, 1470, 1470, 1893, 0, 0, 1603, - 1470, 0, 0, 869, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1352, 0, 0, 1893, 869, 869, 869, - 1602, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 567, 0, 869, 0, 0, 0, 869, 0, 0, 869, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1598, 0, 0, 0, 0, 1599, 0, - 0, 0, 824, 0, 0, 0, 0, 0, 824, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 869, 0, 0, 0, 0, 0, 981, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1893, 1893, 0, 1893, 0, 0, 0, 1598, - 1676, 0, 0, 1677, 1599, 0, 0, 1678, 1679, 0, - 0, 0, 0, 1998, 0, 0, 1602, 0, 0, 0, - 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, - 0, 1603, 1471, 1998, 0, 0, 0, 0, 0, 1687, - 0, 0, 2905, 0, 0, 0, -2183, 0, 0, 0, - 869, 869, 869, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1998, 567, 0, 1468, 0, 567, 0, - 1602, 0, 0, 1689, 567, 0, 0, 0, 0, 0, - 0, 0, 1602, 0, 0, 0, 1999, 0, 0, 0, - 0, 0, 0, 1655, 869, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1999, 0, 0, 2148, - 0, 0, 1602, 2199, 0, 1598, 0, 0, 0, 1602, - 1599, 567, 0, 0, 1015, 567, 0, 0, 568, 2689, - 1601, 0, 0, 0, 0, 0, 1999, 1603, 0, 3297, - 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1468, 1468, 0, 0, 0, 824, 0, 0, 0, - 824, 0, 0, 1602, 0, 0, 0, 1602, 0, 0, - 0, -2183, 0, 1602, 0, 3008, 0, 0, 0, 0, - 1598, 0, 3017, 2286, 0, 1599, 1601, 0, -2183, 2267, - 0, 1603, 0, -2183, 0, 0, 0, 1602, 0, 0, - 0, 0, 0, 1603, 0, 869, 0, 0, 0, 567, - 0, 1128, 0, 567, 567, 0, 0, 3045, 567, 0, - 0, 1233, 1893, 1821, 1893, 0, 1938, 0, 0, 0, - 0, 0, -2183, 1603, 0, 0, 0, 0, 0, 0, - 1603, 0, 1471, 0, 0, 0, 0, 567, 0, 1821, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1341, 0, 0, 0, 567, 567, 567, 567, 1821, 567, - 567, 567, 567, 567, 0, 1356, 1358, 1361, 1363, 1365, - 0, 0, 0, 0, 1603, 0, 0, 0, 1603, 1698, - 0, 1598, 0, 0, 1603, 0, 1599, 0, 0, 2441, - 0, 0, 1601, 0, 2000, 2001, 2002, 869, 2003, 2004, - 2005, 2006, 2007, 2008, 0, 0, 0, 0, 1603, 0, - 3198, 0, 568, 568, 2000, 2001, 2002, 1463, 2003, 2004, - 2005, 2006, 2007, 2008, 1598, 0, 0, 0, 0, 1599, - 0, 0, 0, 0, 0, 0, 1938, 0, 0, 2862, - 0, 0, 0, 1893, 2000, 2001, 2002, 0, 2003, 2004, - 2005, 2006, 2007, 2008, 1468, 0, 0, 1601, 0, 0, + 0, 1468, 1128, 1128, 1047, 11, 0, 0, 0, 0, + 0, 869, 2826, 0, 1809, 1048, 869, 1821, 0, 0, + 1596, 0, 0, 1604, 0, 0, 1599, 0, 0, 869, + 0, 1598, -1929, 14, 15, 0, -1914, 0, 1599, -1914, + 0, 0, 0, 73, 0, -1914, 869, -1929, 3170, 0, + 869, 1049, -1929, 0, 0, 0, 1873, -1929, 0, 0, + 0, 1599, 0, 0, 0, 0, -1929, 0, 1602, 0, + 0, -1929, 2059, 0, 1601, 0, 824, 0, 1023, 0, + 23, 0, 1603, 0, 0, 0, -1914, 824, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1050, 0, + 0, 0, 0, -1929, 0, 1051, 1599, 0, 3732, 0, + 0, -1914, 0, 0, 0, 0, 0, 0, 1893, 0, + 869, 0, 1614, 0, -1929, 0, 0, 0, 869, 0, + 0, 0, 0, 0, 1626, 0, 0, 0, 0, 0, + 0, 1938, 0, 0, 868, 0, 0, 1052, 876, 0, + 981, 0, 0, 0, 0, 981, 0, 567, 567, 0, + 567, 981, 0, 1655, 0, 0, 1053, 0, 0, 0, + 0, 874, 0, 0, 0, -1929, 0, 0, -1929, 0, + 0, 0, 0, 0, -1929, 0, 1596, 0, 0, 0, + 0, 0, 0, 0, 0, 1604, 3279, 1598, 0, 0, + -1914, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 914, -1914, 0, 0, 0, 0, 1601, 1599, 919, 0, + 922, 0, 926, 0, 0, -1929, 0, 26, 27, 28, + 0, -1914, 0, -1914, -1914, 0, 0, 0, 0, 1054, + 1468, 1468, 0, 0, 2060, 0, 1468, 0, 532, 0, + -1929, 903, 903, 0, 903, 0, 0, 0, 0, 0, + 0, 1031, 0, 567, 2034, 0, 0, 0, 1128, 1128, + -1914, 869, 0, -1914, -1914, -1914, 0, 0, 822, 0, + 822, 0, 0, 822, 0, 0, 0, 0, 822, 0, + 1128, 822, 0, 822, 33, 0, 0, 822, 0, 567, + 0, 567, 0, 0, 0, 35, 0, 0, 0, 1676, + 874, 0, 1677, 0, 0, 0, 1678, 1679, 0, 0, + 0, 0, 1601, 0, 0, 0, 0, 0, 0, 37, + 0, 0, 0, 38, 0, 0, 0, 0, 0, -1929, + 0, 0, 0, 0, 0, 0, 0, 0, 1687, 0, + -1929, 0, 0, 0, 39, -2193, 0, 0, 1596, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 40, 1598, + -1929, 0, -1929, -1929, 0, 0, 1601, 0, 0, 43, + 0, 0, 1689, 1599, 0, 0, 0, 0, 1601, 0, + 0, 1602, 0, 0, 0, 0, 44, 0, 0, 0, + 0, 0, 0, 0, 0, 1603, 0, 0, 0, -1929, + 2150, 0, -1929, -1929, -1929, 0, 0, 0, 1601, 0, + 45, 0, 568, 567, 0, 1601, 0, 0, 568, 0, + 0, 0, 823, 73, 46, 0, 0, 1676, 0, 568, + 1677, 0, 0, 0, 1678, 1679, 0, 0, 2682, 0, + 0, 0, 0, 568, 568, 0, 0, 0, 0, 3447, + 0, 0, 0, 981, 0, 0, 1468, 0, 0, 1601, + 0, 0, 0, 1601, 0, 0, 1687, 0, 0, 1601, + -2193, 0, 0, -2193, 0, 0, 823, 823, 0, 1602, + 0, 0, 0, 0, 1128, 0, 0, -2193, 0, 0, + 0, 0, -2193, 1603, 0, 1601, 0, 0, 0, 2253, + 1689, 869, 1676, 869, 0, 1677, 0, 0, 0, 1678, + 1679, 568, 0, 0, 869, 0, 0, 2269, 0, 0, + 3524, 0, 0, 0, 0, 0, 0, 0, 0, 1468, + 0, -2193, 0, 0, 824, 0, 824, 0, 0, 824, + 0, 1687, 0, 0, 824, 1599, 0, 824, -2193, 824, + 0, 0, 0, 824, 869, 0, 567, 0, 0, 0, + 3565, 0, 0, 0, 0, 0, 2994, 0, 2320, 2322, + 0, 0, 0, 0, 2325, 1689, 0, 1821, 567, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1698, 567, + 2346, 567, 1821, 0, 567, 0, 0, 0, -2193, 0, + 0, 0, 0, 0, 567, 0, 567, 0, 0, 0, + 0, 0, 0, 0, 0, -2193, 0, 0, 981, 567, + -2193, 1602, 0, 981, 567, 0, 0, 0, 567, 567, + 1821, 567, 0, 567, 567, 1603, 0, 0, 0, 73, + 0, 2997, 0, 0, 0, 0, 0, 0, 950, 0, + 0, 0, 0, 957, 0, 2416, 0, 0, 0, -2193, + 0, 0, 0, 1352, 0, 869, 869, 869, 869, 869, + 869, 0, 0, -2193, 1676, 0, 0, 1677, 0, 0, + 0, 1678, 1679, 1680, 1681, 2444, 1682, 1683, 1684, 0, + -2193, -2193, 0, 0, 0, -2193, 0, 0, 0, 0, + 0, 0, 0, 1685, 0, 0, 2505, 0, 0, 3635, + 0, 0, 0, 1687, 1042, 0, 1698, 0, 0, 1043, + 1688, 0, 2201, 0, 0, 0, 0, 1602, 0, 0, + 0, 0, 0, 0, -2193, 0, 0, 0, 0, 0, + 0, 1603, 0, 0, 0, 0, 0, 1689, 0, 0, + 0, 0, 0, 0, 0, 0, 1468, 1468, 1468, 1468, + 1468, 1468, 0, 0, 1468, 1468, 1468, 1468, 1468, 1468, + 1468, 1468, 1468, 1468, 0, 0, 0, 0, 1044, 0, + 0, 1602, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1698, 903, 1602, 567, 1603, 0, 0, 0, 0, + 0, 0, 0, -2193, 0, 0, 0, 1603, 869, 0, + 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 0, -2193, + 0, 822, 0, 1602, 0, 0, 0, 822, 0, 0, + 1602, 1601, 0, 567, 0, 0, 0, 1603, 0, 567, + 0, 0, 0, 0, 1603, 1690, 0, 0, 0, 2615, + 2615, 1045, 0, 0, 0, 0, 0, 0, 3524, 0, + 0, 0, 1691, 0, 0, 0, 0, 1692, 0, 0, + 0, 0, 0, 0, 1602, 0, 0, 0, 1602, 0, + 0, 0, 0, 0, 1602, 1601, 0, 1046, 1603, 0, + 1693, 1694, 1603, 0, -2193, 0, 0, 0, 1603, 0, + 0, 0, 0, 1047, 0, 0, 1695, 0, 1015, 0, + 1602, 0, 0, 0, 1048, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1603, 567, 0, 0, 0, 0, + 567, -2193, 0, 0, 0, 567, 0, 0, 1705, 1706, + 1707, 1708, 1709, 1710, 0, 0, 1696, 0, 1676, 1697, + 1049, 1677, 0, 73, 0, 1678, 1679, 0, 0, 1468, + 1468, 0, 0, 1698, 0, 568, 1699, 0, 0, 0, + 0, 1229, 0, 0, 0, 0, 0, 0, 2150, 0, + 0, 0, 0, 0, 1468, 0, 0, 1687, 0, 0, + 0, 0, 0, 0, -2193, 0, 0, 1050, 0, 0, + 0, 0, 1601, 0, 1051, 1233, -2193, 0, 0, 0, + 0, 822, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, + 0, 1689, 1079, 567, 0, 1991, 0, 822, 0, 1992, + 1993, 822, 2269, 0, 1994, 1995, 1996, 0, 0, 0, + 0, 0, 0, 1471, 1341, 0, 1052, 0, 0, 0, + 0, 2985, 0, 0, 0, 0, 0, 0, 0, 1356, + 1358, 1361, 1363, 1365, 0, 1053, 1700, 0, 1601, 0, + 0, 0, 567, 0, 0, 1468, 1676, 1128, 567, 1677, + 0, 0, 0, 1678, 1679, 0, 0, 824, -2193, -2193, + -2193, 0, 0, 824, 0, 0, 1079, 0, 0, 1991, + 1893, 0, 0, 1992, 1993, 0, 0, 0, 1994, 1995, + 1996, 1463, 0, 0, 0, 1687, 0, 0, 0, -2193, + 0, 1079, 1688, 0, 1991, 3260, 0, 0, 1992, 1993, + 0, 0, 0, 1994, 1995, 1996, -2193, 0, 1054, 0, + 0, -2193, 0, 0, 0, 0, 0, 0, 0, 1689, + 3261, 0, 0, 0, 0, 0, 0, 0, 0, 568, + 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1701, 0, + -2193, 1702, 1703, 1704, 1893, 1705, 1706, 1707, 1708, 1709, + 1710, 869, 0, 0, 0, 0, 0, 0, 1984, 0, + 0, 1352, 0, 0, 1893, 869, 869, 869, 0, 0, + 0, 0, 0, 0, 0, 0, 567, 0, 869, 823, + 0, 0, 869, 1601, 0, 869, 0, 0, 0, 0, + 1655, 0, 0, 0, 0, 0, 0, 1698, 1998, 0, + 0, 0, 0, 0, 0, 0, 1602, 1690, 0, 0, + 2201, 0, 0, 1471, 0, 0, 0, 0, 0, 0, + 1603, 0, 0, 0, 1691, 0, 2692, 0, 869, 1692, + 0, 0, 0, 0, 981, 0, 0, 824, 0, 0, + 568, 0, 0, 0, 0, 0, 0, 0, 1893, 1893, + 1601, 1893, 0, 824, 0, 0, 0, 824, 0, 0, + 1602, 0, 0, 0, 0, 0, 0, 0, 1695, 0, + 0, 1999, 1998, 0, 1603, 0, 0, 0, 0, 0, + 532, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1807, 0, 0, 1998, 2910, 1811, + -2193, 0, 1079, 0, 0, 1991, 869, 869, 869, 1992, + 1993, 0, 1843, 0, 1994, 1995, 1996, 0, 0, 0, + 567, 0, 1468, 0, 567, 1698, 0, 0, 0, 0, + 567, 0, 0, 1868, 0, 0, 0, 1601, 0, 0, + 0, 0, 0, 0, 0, 1999, 0, 0, 0, 0, + 0, 0, 869, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2150, 0, 0, + 1999, 0, 0, 0, 0, 0, 0, 1602, 0, 567, + 0, 0, 0, 567, 0, 0, 0, 0, 0, 1488, + 0, 1603, 0, 0, 0, 823, 0, 823, 0, 0, + 0, 0, 0, 1898, 0, 0, 823, 0, 0, 1468, + 1468, 1916, -2193, 0, 0, 0, 1526, 0, 0, 1705, + 1706, 1707, 1708, 1709, 1710, 0, 0, 0, 1700, 0, + 0, 0, 0, 3015, 0, 0, 0, 0, 0, 0, + 3024, 0, 0, 1602, 0, 2867, 0, 2269, 0, 0, + 0, 1601, 1471, 1471, 0, 0, 0, 1603, 1471, 0, + 0, 568, 0, 869, 0, 0, 0, 567, 0, 1128, + 0, 567, 567, 0, 0, 3052, 567, 0, 0, 0, + 1893, 1821, 1893, 0, 1938, 0, 1660, 0, 0, 2000, + 2001, 2002, 0, 2003, 2004, 2005, 2006, 2007, 2008, 0, + 0, 0, 0, 0, 1601, 567, 0, 1821, 0, 0, + 0, 0, 0, 0, 0, 0, 1601, 0, 1998, 0, + 0, 0, 0, 567, 567, 567, 567, 1821, 567, 567, + 567, 567, 567, 0, 0, 0, 0, 0, 0, 1601, + 1701, 0, 0, -2193, -2193, -2193, 0, 1705, 1706, 1707, + 1708, 1709, 1710, 0, 2048, 568, 568, 0, 2444, 0, + 0, 0, 0, 2000, 2001, 2002, 869, 2003, 2004, 2005, + 2006, 2007, 2008, 0, 0, 0, 0, 0, 0, 3157, + 0, 0, 0, 0, 1601, 0, 0, 0, 2000, 2001, + 2002, 1999, 2003, 2004, 2005, 2006, 2007, 2008, 1602, 0, + 0, 0, 0, 0, 0, 0, 1938, 0, 0, 0, + 0, 0, 1603, 1893, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1468, 0, 0, 0, 0, 0, 567, 0, 0, 0, 0, 0, 0, 869, 869, 869, - 869, 0, 823, 0, 0, 0, 0, 0, 0, 0, - 0, 1468, -2183, 0, 1468, 0, 0, 0, 567, 981, - 1598, 0, 0, 0, 0, 1599, 0, 3271, 0, 0, - 1470, 1470, 1470, 1470, 1470, 1470, 0, 0, 1470, 1470, - 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 0, 0, - 567, 0, 0, 0, 0, 0, 0, 3279, 567, 0, - 0, 0, 0, 568, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1417, 0, - 836, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3307, 0, 822, 0, 0, 0, 0, 0, 1601, 0, - 0, 1471, 1471, 0, 1128, 1598, 0, 1471, 0, 0, - 1599, 3321, 0, 0, 0, 0, 2267, 0, 0, 0, - 0, 0, 2148, 0, -2183, 0, 0, 0, 0, 0, - 0, 1705, 1706, 1707, 1708, 1709, 1710, 1821, 0, 0, - 0, 1601, 0, 1893, 1418, 1419, 0, 0, 0, 0, - 0, 0, 1602, 0, 0, 0, 981, 567, 1468, 0, - 0, 0, 0, 0, 869, 0, 0, 0, 1655, 0, - 1807, 0, 0, 0, 0, 1811, 0, 0, 0, 0, - 0, 3377, 0, 0, 0, 1420, 1421, 0, 1843, 1422, - 1423, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1655, 0, 0, 0, 1601, 1602, 1868, - 0, 0, 1488, 0, 0, 0, 0, 0, 823, 1598, - 823, 0, 0, 0, 1599, 0, 0, 0, 0, 823, - 73, 1470, 1470, 0, 0, 0, 0, 0, 0, 1526, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1598, 0, 0, 3040, 0, 1599, - 0, 0, 0, 3394, 0, 0, 1424, 1425, 1893, 0, - 0, 0, 0, 1603, 0, 0, 0, 0, 0, 1898, - 0, 0, 0, 2441, 568, 0, 0, 1916, 0, 0, - 0, 0, 1601, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1660, - 3432, 0, 0, 0, 0, 1468, 0, 0, 0, 0, - 1598, 0, 0, 0, 1602, 1599, 1598, 0, 0, 1603, - 0, 1599, 0, 1426, 1427, 1428, 1429, 1430, 1431, 1432, - 1433, 3448, 0, 1434, 1435, 0, 73, 1470, 567, 1598, - 0, 0, 0, 2243, 1599, 567, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 3467, 0, 0, 0, 886, 0, 568, 568, - 73, 0, 0, 0, 0, 0, 0, 0, 0, 1602, - 3218, 0, 0, 1598, 0, 3479, 0, 0, 1599, 0, - 1471, 0, 0, 3008, 0, 0, 1601, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1436, 1437, - 0, 0, 0, 0, 567, 0, 0, 0, 0, 567, - 2048, 0, 0, 0, 0, 0, 0, 1655, 0, 0, - 0, 1601, 0, 0, 0, 1603, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 567, 0, 0, 0, 1438, - 1439, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 567, 567, 0, 0, - 0, 0, 0, 0, 0, 1418, 1419, 0, 0, 0, - 0, 0, 0, 0, 869, 0, 3198, 0, 0, 0, - 1602, 567, 0, 0, 0, 0, 1598, 1601, 0, 0, - 1603, 1599, 0, 1601, 0, 0, 0, 0, 824, 0, - 869, 0, 0, 3557, 0, 0, 1420, 1421, 73, 0, - 1422, 1423, 0, 0, 0, 0, 1601, 886, 0, 0, - 0, 0, 1468, 1602, 1128, 0, 567, 1031, 0, 1031, - 0, 0, 0, 0, 567, 0, 0, 0, 0, 1440, - 1441, 0, 0, 0, 0, 568, 568, 0, 568, 0, - 0, 0, 0, 0, 0, 1128, 0, 0, 0, 3321, - 1601, 0, 0, 1442, 1443, 0, 0, 0, 0, 0, - 869, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1424, 1425, 1602, + 869, 0, 0, 0, 0, 0, 1655, 0, 0, 0, + 0, 1468, 0, 0, 1468, 0, 0, 0, 567, 981, + 0, 0, 0, 0, 0, 1602, 0, 0, 3237, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1603, + 0, 1655, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 567, 0, 0, 1601, 0, 0, 0, 3246, + 567, 0, 0, 0, 2245, 0, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 869, 1603, 0, 0, 0, 0, 0, 1471, 1471, 1471, - 1471, 1471, 1471, 0, 0, 1471, 1471, 1471, 1471, 1471, - 1471, 1471, 1471, 1471, 1471, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3448, - 0, 0, 0, 0, 1603, 0, 0, 1128, 0, 0, - 2252, 568, 2254, 0, 1426, 1427, 1428, 1429, 1430, 1431, - 1432, 1433, 3557, 2263, 1434, 1435, 823, 0, 823, 0, - 0, 823, 0, 1601, 1602, 0, 823, 0, 0, 823, - 0, 823, 0, 0, 0, 823, 0, 2072, 0, 2076, - 73, 0, 3198, 0, 0, 0, 0, 735, 0, 0, - 1470, 1470, 0, 2301, 981, 981, 0, 3557, 981, 0, - 1603, 0, 0, 0, 0, 0, 2034, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 567, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1655, 0, 1436, - 1437, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1243, 3198, 736, 0, 0, 0, 1244, 0, - 3557, 0, 0, 0, 0, 0, 1256, 0, 1598, 0, - 737, 0, 0, 1599, 0, 0, 0, 0, 0, 0, - 1438, 1439, 0, 0, 0, 0, 1257, 0, 1602, 0, - 0, 0, 0, 0, 0, 1603, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 981, 0, 1471, 1471, - 0, 2160, 0, 0, 2425, 2426, 2428, 2429, 2430, 2431, - 738, 2267, 0, 1602, 0, 0, 3321, 0, 0, 2267, - 739, 0, 1258, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 740, 0, 0, 0, 0, 741, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1245, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 742, 0, 0, - 1440, 1441, 0, 0, 0, 0, 0, 0, 0, 1602, - 0, 0, 1143, 1143, 0, 1602, 0, 0, 0, 73, - 0, 0, 0, 0, 1442, 1443, 0, 0, 0, 1603, - 0, 0, 0, 1470, 0, 0, 0, 0, 1602, 0, - 0, 743, 0, 0, 1471, 3554, 744, 0, 0, 1259, + 0, 0, 3274, 0, 822, 3047, 0, 0, 0, 0, + 0, 0, 568, 568, 0, 568, 1128, 0, 0, 0, + 0, 1471, 1602, 3288, 0, 0, 0, 0, 2269, 0, + 0, 0, 0, 0, 2150, 0, 1603, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1821, + 0, 0, 0, 0, 0, 1893, 0, 0, 0, 0, + 0, 0, 0, 0, 2254, 0, 2256, 0, 981, 567, + 1468, 0, 0, 0, 0, 0, 869, 2265, 0, 2000, + 2001, 2002, 0, 2003, 2004, 2005, 2006, 2007, 2008, 0, + 0, 0, 0, 3344, 0, 73, 0, 0, 0, 0, + 0, 0, 1079, 0, 0, 1991, 0, 0, 0, 1992, + 1993, 0, 0, 0, 1994, 1995, 1996, 2303, 568, 0, + 0, 0, 0, 0, 0, 0, 886, 3358, 0, 0, + 73, 1601, 1893, 823, 0, 823, 1602, 0, 823, 0, + 3183, 0, 0, 823, 0, 0, 823, 2444, 823, 0, + 1603, 0, 823, 0, 2072, 0, 2076, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3256, 0, 0, 0, 1603, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 568, 1601, 0, 2580, 0, 0, - 0, 0, 1602, 0, 0, 0, 0, 0, 1286, 0, - 0, 0, 1332, 1339, 0, 0, 568, 0, 0, 0, - 1260, 0, 73, 0, 73, 0, 0, 568, 0, 568, - 3285, 1261, 568, 0, 0, 0, 0, 0, 745, 0, - 0, 0, 568, 1262, 568, 0, 0, 0, 0, 0, - 1603, 0, 0, 746, 0, 0, 1603, 568, 0, 0, - 0, 0, 568, 0, 1246, 1390, 568, 568, 73, 568, - 0, 568, 568, 0, 0, 1263, 0, 0, 0, 1603, - 0, 0, 0, 1414, 0, 73, 0, 0, 747, 1462, - 0, 748, 1464, 0, 0, 1475, 1478, 1483, 1486, 0, - 0, 0, 749, 0, 0, 750, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1602, 0, 0, 0, 0, - 0, 0, 0, 1603, 1264, 751, 0, 1470, 1248, 0, - 1265, 0, 0, 0, 0, 0, 0, 0, 0, 752, - 1530, 1332, 0, 0, 0, 0, 0, 754, 0, 0, - 0, 0, 0, 0, 0, 1266, 0, 755, 0, 0, - 1267, 0, 1617, 756, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1268, 0, 0, 0, - 0, 0, 1634, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 757, 0, 1645, 1646, 1647, 0, 1652, 1656, - 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, - 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1685, 0, 568, 0, 1719, 1250, 1603, 0, 0, 0, - 1687, 0, 0, 0, 73, 0, 0, 1688, 0, 1243, - 0, 0, 1530, 1530, 0, 1244, 0, 0, 0, 823, - 0, 0, 0, 1256, 0, 823, 0, 0, 0, 0, - 0, 2600, 0, 0, 1689, 0, 0, 2076, 0, 0, - 0, 0, 0, 1257, 1470, 0, 0, 0, 0, 1759, - 0, 0, 0, 1775, 1780, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1143, 1143, 1675, 0, 0, 0, - 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, - 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 0, 1258, - 0, 0, 0, 0, 0, 0, 0, 1471, 1471, 0, - 1685, 0, 0, 0, 1686, 0, 0, 0, 0, 0, - 1687, 0, 0, 0, 0, 0, 0, 1688, 0, 0, - 1245, 2160, 0, 0, 0, 0, 568, 0, 1332, 0, - 0, 1660, 1690, 0, 0, 0, 0, 2828, 0, 1332, - 0, 0, 0, 0, 1689, 0, 0, 0, 0, 1691, - 0, 2844, 2845, 2847, 1692, 0, 0, 1602, 0, 0, - 0, 0, 0, 0, 1332, 0, 2860, 0, 0, 0, - 2863, 0, 0, 2866, 0, 0, 0, 1693, 1694, 0, - 0, 0, 0, 0, 0, 0, 1259, 0, 0, 0, - 0, 0, 0, 1695, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 823, 0, 0, - 0, 0, 0, 0, 0, 0, 2878, 0, 0, 568, - 0, 0, 0, 823, 0, 0, 0, 823, 0, 0, - 0, 0, 0, 1696, 0, 0, 1697, 1260, 0, 0, - 0, 0, 1690, 0, 0, 0, 0, 0, 1261, 0, - 1698, 0, 1981, 1699, 0, 0, 0, 0, 0, 1691, - 1262, 0, 0, 0, 1692, 0, 0, 0, 568, 0, - 0, 3574, 0, 0, 2743, 0, 0, 0, 1603, 0, - 0, 1246, 0, 0, 0, 0, 0, 1693, 1694, 0, - 0, 0, 1263, 0, 2912, 2913, 2914, 0, 0, 0, - 0, 0, 0, 1695, 0, 0, 0, 0, 0, 0, - 1471, 0, 0, 0, 0, 1483, 0, 1483, 1483, 0, + 3396, 0, 0, 0, 0, 1468, 0, 1655, 0, 1602, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1143, 1143, 0, 0, 0, 0, 0, 1471, 0, 0, - 0, 2368, 0, 1696, 0, 1248, 1697, 1265, 0, 0, - 0, 0, 1143, 1700, 0, 0, 0, 0, 0, 0, - 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, - 0, 0, 1266, 0, 0, 0, 0, 2369, 0, 0, + 0, 1602, 0, 1603, 0, 0, 0, 0, 0, 0, + 0, 3412, 0, 0, 0, 1603, 0, 0, 567, 0, + 0, 0, 0, 0, 1602, 567, 0, 0, 2428, 2429, + 2431, 2432, 2433, 2434, 0, 0, 0, 0, 1603, 0, + 0, 0, 0, 0, 3432, 0, 0, 0, 1471, 1471, + 1471, 1471, 1471, 1471, 0, 0, 1471, 1471, 1471, 1471, + 1471, 1471, 1471, 1471, 1471, 1471, 0, 3444, 0, 1602, + 824, 0, 0, 0, 0, 3015, 0, 0, 2162, 0, + 73, 0, 0, 1603, 0, 0, 0, 0, 0, 886, + 0, 0, 0, 0, 0, 0, 567, 1675, 0, 0, + 0, 567, 1676, 1601, 0, 1677, 0, 0, 0, 1678, + 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, -2193, 0, + 0, 0, 0, 0, 0, 0, 0, 567, 0, 0, + 0, 1685, 0, 0, 0, 1686, 0, 0, 0, 0, + 0, 1687, 0, 0, 0, 567, 567, 0, 1688, 0, + 0, 0, 0, 1243, 0, 0, 0, 0, 0, 1244, + 0, 0, 0, 869, 0, 3157, 0, 1256, 0, 0, + 567, 2581, 0, 0, 0, 1689, 0, 0, 0, 0, + 1602, 0, 0, 0, 0, 0, 0, 1257, 0, 869, + 1676, 1999, 3573, 1677, 1603, 0, 0, 1678, 1679, 1680, + 1681, 0, 1682, 1683, 1684, 0, 0, 0, 0, 0, + 0, 1468, 0, 1128, 73, 567, 1031, 0, 1031, 1685, + 0, 568, 0, 0, 567, 0, 0, 0, 0, 1687, + 0, 0, 0, 1258, 0, 0, 1688, 0, 0, 0, + 0, 0, 0, 568, 0, 1128, 0, 0, 0, 3288, + 0, 1471, 1471, 0, 568, 0, 568, 0, 0, 568, + 869, 0, 0, 1689, 1245, 0, 0, 1655, 0, 568, + 0, 568, 0, 1690, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 568, 0, 0, 0, 0, 568, + 1691, 0, 0, 568, 568, 1692, 568, 0, 568, 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1268, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1693, 1694, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 568, 0, 0, 0, 0, 0, 0, + 1259, 0, 0, 0, 1695, 0, 0, 869, 0, 0, + 0, 0, 0, 0, 0, 0, 1602, 0, 0, 0, + 0, 2015, 0, 0, 0, 0, 2016, 0, 0, 0, + 1603, 1690, 0, 0, 0, 0, 0, 1471, 0, 0, + 0, 0, 0, 0, 1696, 0, 0, 1697, 1691, 0, + 3412, 1260, 0, 1692, 0, 0, 0, 0, 1128, 0, + 0, 1698, 1261, 0, 1699, 0, 0, 0, 0, 0, + 0, 0, 0, 3573, 1262, 0, 1693, 1694, 0, 2000, + 2001, 2002, 0, 2003, 2004, 2005, 2006, 2007, 2008, 0, + 0, 0, 1695, 0, 0, 1246, 0, 0, 73, 0, + 0, 0, 0, 3157, 0, 0, 1263, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 981, + 981, 0, 3573, 981, 3570, 0, 0, 0, 0, 568, + 0, 2034, 1696, 0, 0, 1697, 0, 0, 0, 0, + 0, 0, 567, 0, 0, 0, 0, 0, 0, 1698, + 0, 0, 1699, 0, 0, 2371, 823, 0, 0, 1248, + 0, 1265, 823, 0, 1700, 0, 0, 0, 2601, 0, + 3157, 0, 0, 0, 2076, 0, 0, 3573, 0, 0, + 0, 0, 73, 0, 73, 0, 1266, 0, 1602, 0, + 0, 2372, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1603, 0, 0, 0, 0, 1268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2832, 0, 981, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2848, 2849, + 2851, 2269, 0, 0, 0, 0, 3288, 0, 0, 2269, + 0, 2865, 1700, 0, 0, 2868, 0, 0, 2871, 0, + 2162, 0, 0, 0, 0, 568, 1250, 0, 0, 0, + 1660, 0, 0, 0, 0, 73, 1701, 0, 0, 1702, + 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, + 0, 0, 0, 0, 0, 0, 73, 0, 0, 0, + 0, 2883, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1676, 0, 0, 1677, 0, 0, + 735, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 1143, + 1143, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1685, 0, 0, 823, 2975, 0, 0, + 0, 0, 0, 1687, 0, 0, 0, 0, 568, 0, + 1688, 0, 823, 0, 1701, 0, 823, 1702, 1703, 1704, + 0, 1705, 1706, 1707, 1708, 1709, 1710, 736, 0, 2917, + 2918, 2919, 0, 0, 0, 0, 0, 1689, 0, 0, + 0, 0, 0, 737, 0, 0, 0, -48, 0, 0, + 0, 0, 0, 0, 0, 1286, 0, 568, 0, 1332, + 1339, 1471, 1471, 2746, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 3, 4, 73, 0, 0, 0, 0, 0, + 0, 0, 0, 738, 0, 5, 0, 0, 0, 0, + 6, 0, 0, 739, 0, 0, 0, 0, 0, 7, + 0, 73, 1390, 0, 0, 0, 740, 0, 0, 0, + 0, 741, 0, 8, 0, 0, 0, 0, 0, 0, + 1414, 0, 9, 0, 10, 1690, 1462, 0, 0, 1464, + 0, 0, 1475, 1478, 1483, 1486, 11, 0, 12, 0, + 742, 0, 1691, 0, 0, 0, 0, 1692, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3036, - 0, 0, 1250, 0, 0, 0, 0, 2122, 0, 0, - 0, 0, 0, 1700, 0, 1701, 2126, 0, 1702, 1703, - 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, - 2157, 0, 0, 0, 1471, 1984, 0, 0, 0, 0, + 0, 0, 0, 0, 14, 15, 16, 0, 0, 0, + 1693, 1694, 0, 0, 0, 17, 3043, 1530, 1332, 0, + 0, 18, 0, 0, 743, 0, 1695, 0, 0, 744, + 19, 568, 20, 21, 0, 0, 0, 0, 0, 1617, + 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, + 0, 23, 0, 0, 0, 0, 0, 0, 0, 1634, + 0, 0, 0, 0, 0, 0, 1696, 0, 0, 1697, + 0, 1645, 1646, 1647, 0, 1652, 1656, 24, 0, 0, + 0, 0, 0, 1698, 0, 0, 1699, 0, 0, 0, + 0, 0, 0, -1534, 0, 0, 0, 0, 0, 0, + 0, 745, 0, 0, 0, 0, 1471, 0, 0, 0, + 0, 1719, 0, 0, 0, 0, 746, 0, 0, 3145, + 25, 0, 0, 0, 0, 0, 0, 0, 0, 1530, + 1530, 0, 0, 1471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2171, 0, 0, 0, 0, 0, 0, 0, 2176, 0, - 0, 0, 0, 0, 2180, 2181, 2182, 2183, 2184, 2185, - 2186, 2187, 0, 0, 0, 0, 2196, 2197, 0, 0, - 0, 2210, 0, 0, 0, 2213, 0, 0, 2221, 2222, - 2223, 2224, 2225, 2226, 2227, 2228, 2229, 0, 0, 2230, - 0, 3186, 0, 0, 0, 0, 1143, 568, 1332, 0, - 0, 568, 0, 0, 0, 0, 0, 2072, 0, 0, - 0, 0, 0, 0, 0, 1701, 2256, 0, 1702, 1703, - 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, + 0, 747, 0, 0, 748, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 749, 1759, 0, 750, 0, + 1775, 1780, 0, 0, 0, 568, 0, 0, 0, 568, + 0, 1143, 1143, 0, 0, 2072, 1700, 0, 751, 0, + 3199, 3200, 3201, 3202, 0, 0, 0, 0, 26, 27, + 28, 0, 752, 0, 0, 0, 29, 0, 0, 30, + 754, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 755, 0, 1676, 0, 0, 1677, 756, 0, 0, 1678, + 1679, 0, 0, 0, 2970, 0, 0, 0, 2162, 0, + 31, 0, 0, 0, 0, 1332, 0, 0, 0, 32, + 1676, 0, 0, 1677, 0, 757, 1332, 1678, 1679, 1680, + 1681, 1687, 1682, 1683, 1684, 33, 0, 0, -2193, 0, + 0, 0, 34, 0, 0, 0, 35, 0, 0, 1685, + 0, 1332, 1471, 0, 0, 0, 0, 0, 36, 1687, + 0, 0, 0, 0, 0, 1689, 1688, 0, 1701, 0, + 37, 1702, 1703, 1704, 38, 1705, 1706, 1707, 1708, 1709, + 1710, 0, 0, 0, 0, 2168, 0, 0, 0, 0, + 0, 0, 568, 1689, 0, 39, 568, 568, 0, 0, + 0, 568, 0, 0, 0, 0, 0, 0, 0, 40, + 0, 0, 41, 0, 0, 42, 0, 0, 0, 0, + 43, 0, 0, 0, 0, 0, 0, 0, 0, 3331, + 568, 2998, 0, 0, 0, 0, 0, 44, 0, 1981, + 0, 0, 0, 0, 0, 0, 0, 0, 568, 568, + 568, 568, 0, 568, 568, 568, 568, 568, 0, 0, + 0, 45, 0, -2193, 0, 0, 0, 1471, 0, 0, + 0, 0, 0, 0, 0, 46, 0, 0, -48, 0, + -2193, 0, 0, 0, 0, -2193, 0, 0, 0, 0, + 0, 1690, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1483, 0, 1483, 1483, 0, 0, 1691, 0, + 0, 0, 0, 1692, 0, 0, 0, 1143, 1143, 0, + 0, 0, 0, 0, -2193, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1693, 1694, 0, 1143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1695, 0, 0, 2072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1646, 1647, 2963, 0, 0, 0, 2160, 0, - 0, 3234, 3235, 3236, 3237, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1676, 0, 0, + 1677, 1698, 0, 2601, 1678, 1679, 1680, 1681, 0, 1682, + 1683, 1684, 1696, 0, 0, 1697, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1685, 0, 0, 1698, + 0, 0, 1699, 0, 0, 0, 1687, 2162, 0, 0, + 0, 0, 0, 1688, 0, 2162, 1676, 0, 0, 1677, + 0, 0, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, + 1684, 0, 0, 0, 2124, 0, 0, 0, 0, 0, + 1689, 0, 0, 2128, 0, 1685, 0, 0, 0, 823, + 0, 0, 0, 0, 0, 1687, 0, 2159, 0, 0, + 0, 0, 1688, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -2193, 0, 0, 2173, 0, 0, + 0, 0, 0, 1471, 0, 2178, 0, 0, 0, 1689, + 0, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 0, + 0, 0, 1700, 2198, 2199, 0, 3542, 0, 2212, 0, + 0, 0, 2215, 0, 568, 2223, 2224, 2225, 2226, 2227, + 2228, 2229, 2230, 2231, 0, 0, 2232, 0, 0, 0, + 0, 0, 3571, 1143, 0, 1332, 0, 0, 1690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1471, 0, 0, 0, 1676, 0, 0, 1677, 0, - 0, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, + 0, 0, 0, 2258, 0, 1691, 0, 0, 0, 0, + 1692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1685, 0, 0, 0, 2968, 0, - 0, 0, 0, 0, 1687, 0, 0, 0, 0, 0, - 0, 1688, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 568, 0, 0, 0, 568, 568, 0, 0, - 0, 568, 0, 2395, 0, 0, 0, 0, 1689, 0, - 1332, 0, 0, 2406, 2407, 0, 0, 0, 0, 0, + 0, 0, 0, 1693, 1694, 0, -2193, 1690, 0, 1646, + 1647, 0, 0, 1705, 1706, 1707, 1708, 1709, 1710, 1695, + 0, 0, 0, 3614, 1691, 0, 0, 0, 0, 1692, + 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, 1704, + 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 0, + 0, 2168, 1693, 1694, 0, 0, 0, 0, 0, 1696, + 0, 0, 1697, 0, 0, 0, 0, 0, 1695, 0, + 0, 0, 0, 0, 0, 0, 1698, 0, 0, 1699, + 0, 0, 0, 3420, 0, 0, 0, 0, 0, 0, + 2601, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3640, 0, 0, 0, 0, 0, 0, 0, 1696, 0, + 2398, 1697, 0, 0, 0, 0, 0, 1332, 0, 0, + 2409, 2410, 0, 0, 0, 1698, 0, 0, 1699, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1676, + 0, 0, 1677, 0, 0, 0, 1678, 1679, 1680, 1681, + 0, 1682, 1683, 1684, 0, 0, 0, 0, 0, 0, + 0, 568, 0, 0, 0, 0, 568, 0, 1685, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1687, 1700, + 0, 0, 0, 0, 0, 1688, 0, 1390, 2513, 0, + 0, 1676, 568, 0, 1677, 0, 2515, 0, 1678, 1679, + 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 0, 0, + 568, 568, 1689, 0, 0, 0, 2531, 2532, 0, 2533, + 1685, 0, 0, 0, 0, 0, 0, 0, 1700, 0, + 1687, 0, 0, 0, 0, 568, 0, 1688, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2559, 2560, + 0, 0, 2258, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1689, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 568, 568, 568, - 568, 0, 568, 568, 568, 568, 568, 0, 0, 0, + 568, 0, 0, 2585, 0, 0, 0, 0, 0, 2162, + 0, 1701, 2595, 0, 1702, 1703, 1704, 0, 1705, 1706, + 1707, 1708, 1709, 1710, 0, 0, 0, 0, 2530, 0, + 1690, 1530, 0, 1332, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1691, 0, 0, + 0, 0, 1692, 0, 0, 0, 0, 0, 0, 0, + 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, + 1708, 1709, 1710, 0, 2632, 1693, 1694, 2636, 0, 0, + 2639, 0, 1690, 0, 0, 0, 0, 0, 1472, 0, + 0, 1695, 0, 0, 0, 0, 0, 0, 0, 1691, + 0, 0, 0, 1676, 1692, 0, 1677, 0, 0, 0, + 1678, 1679, 0, 2651, 0, 0, 0, 2657, 0, 0, + 0, 0, 2662, 2663, 0, 0, 0, 1693, 1694, 0, + 0, 1696, 0, 0, 1697, 0, 0, 0, 0, 0, + 0, 0, 1687, 1695, 0, 0, 0, 0, 1698, -2193, + 0, 1699, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2684, + 0, 0, 2687, 0, 2689, 0, 1689, 0, 0, 0, + 0, 0, 0, 1696, 0, 0, 1697, 0, 0, 0, + 2693, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1713, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3364, 0, - 1390, 2512, 0, 0, 0, 0, 0, 0, 0, 2514, - 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, 1680, - 1681, 0, 1682, 1683, 1684, 0, 1690, 0, 0, 2530, - 2531, 0, 2532, 0, 0, 0, 0, 0, 0, 1685, - 0, 0, 0, 1691, 0, 0, 0, 0, 1692, 1687, + 1759, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3264, 0, 0, 0, 0, 1780, 2230, 0, + 0, 1700, 0, 0, 0, 0, 0, 568, 0, 0, + 0, 0, 0, 1713, 0, 0, 1143, 0, 0, 0, + 0, 0, 0, 0, -2193, 0, 0, 0, 0, 0, + 1676, 2753, 0, 1677, 0, 0, 0, 1678, 1679, 1680, + 1681, -2193, 1682, 1683, 1684, 0, -2193, 0, 1472, 0, + 0, 0, 0, 1700, 0, 0, 0, 0, 0, 1685, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1687, 0, 0, 0, 0, 0, 0, 1688, 0, 0, 0, - 0, 2558, 2559, 0, 0, 2256, 0, -48, 0, 0, - 0, 1693, 1694, 2072, 0, 0, 0, 0, 1471, 0, - 0, 0, 0, 1689, 0, 0, 0, 1695, 0, 0, - 1, 0, 0, 0, 0, 0, 2584, 0, 0, 0, - 2, 2600, 3, 4, 0, 2594, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, - 6, 0, 0, 0, 1530, 0, 1332, 1696, 0, 7, - 1697, 0, 0, 2160, 0, 0, 0, 0, 0, 0, - 0, 2160, 0, 8, 1698, 0, 0, 1699, 0, 0, - 0, 0, 9, 0, 10, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2629, 11, 0, 12, 0, - 0, 2636, 0, 0, 0, 823, 0, 0, 0, 13, - 0, 1690, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 14, 15, 16, 0, 1691, 0, - 0, 0, 0, 1692, 2648, 17, 0, 0, 2654, 0, - 0, 18, 0, 2659, 2660, 0, 0, 0, 0, 0, - 19, 0, 20, 21, 0, 0, 1693, 1694, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, - 568, 23, 1695, 0, 0, 0, 0, 1700, 0, 0, + 0, 0, 0, 0, 0, -2193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2681, 0, 0, 2684, 0, 2686, 0, 24, 0, 0, + 1647, 0, 0, 1689, 0, 0, 0, 1713, 0, 1332, + 0, 0, 0, 1701, 0, 0, 1702, 1703, 1704, 0, + 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 0, 0, + 2650, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1698, 0, 1676, 0, 0, 1677, 0, 0, + 0, 1678, 1679, 1713, 0, 0, 1682, 1683, 1684, 0, + 1713, 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, + 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, + 0, 0, 2668, 1687, 0, 0, 0, 0, 0, 0, + 1688, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1690, 0, 0, 0, 2881, 0, 0, 0, 0, + 0, 1713, 0, 0, 0, 0, 0, 1689, 1691, 1676, + 0, 0, 1677, 1692, 0, 0, 1678, 1679, 1680, 1681, + 0, 1682, 1683, 1684, 0, 1713, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -2193, 1693, 1694, 1685, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1687, 0, + 0, 0, 1695, 0, 0, 1688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2690, 1696, -1524, 0, 1697, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1698, + 0, 0, 0, 1713, 0, 1713, 0, 1472, 1472, 0, + 2009, 0, 1689, 1472, 0, 0, 1713, 0, 0, 1713, + 0, 0, 1696, 0, 1713, 1697, 0, 1713, 0, 0, + 0, 0, 0, 0, 0, 1690, 0, 0, 0, 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, 0, - 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1759, 0, 0, 0, 0, 0, 0, 3530, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1780, 2228, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3555, 0, 0, 1143, 0, 1701, - 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, - 1709, 1710, 2750, 0, 0, 0, 2166, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 26, 27, - 28, 0, 0, 0, 0, 0, 29, 0, 0, 30, - 0, 0, 1700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1691, 0, 0, 0, 2960, 1692, 0, 0, + 0, 0, 0, 2962, 2128, 0, 0, 0, 0, 0, + 0, 1713, 0, 0, 0, 0, 0, -2193, 0, 2971, + 1693, 1694, 0, 0, 1705, 1706, 1707, 1708, 1709, 1710, + 0, 0, 2983, 0, 0, 2986, 1695, 2988, 0, 0, + 0, 0, 0, 0, 0, 2992, 0, 0, 0, 0, + 1690, 0, 0, 2999, 3000, 0, 0, 0, 0, 0, + 3007, 0, 0, 0, 0, 0, 0, 1691, 0, 0, + 0, 0, 1692, 0, 0, 0, 1696, 3021, 0, 1697, + 0, 0, 1700, 0, 0, 0, 0, 0, 3037, 0, + 0, 0, 0, 1698, 0, 1693, 1694, 0, 1713, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1143, 0, + 0, 1695, 0, 0, 0, 1713, 1417, 0, 836, 0, + 0, 0, 0, 0, 0, 0, 1713, 1713, 1713, 0, + 0, 0, 0, 1713, 0, 0, 0, 1713, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3598, 0, 0, 0, 0, 1676, - 31, 3456, 1677, 0, 0, 0, 1678, 1679, 2600, 32, - 1647, 1682, 1683, 1684, 0, 0, 0, 0, 0, 1332, - 0, 0, 0, 0, 3624, 33, 0, 0, 1685, 0, - 0, 0, 34, 1472, 1418, 1419, 35, 0, 1687, 0, - 0, 0, 0, 0, 0, 1688, 0, 0, 36, 0, + 0, 1696, 0, 0, 1697, 3108, 3109, 0, 0, 0, + 0, 1759, 0, 0, 0, 0, 0, 0, 1698, 0, + 0, 1699, 0, 0, 0, 2398, 2398, 0, 0, 0, + 0, 0, 1418, 1419, 0, 0, 0, 0, 3134, 0, + 0, 0, 0, 0, 1701, 0, 1700, 1702, 1703, 1704, + 1713, 1705, 1706, 1707, 1708, 1709, 1710, 3148, 0, 0, + 0, 2898, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1420, 1421, 0, 0, 1422, 1423, 0, + 0, 0, 0, 0, 1676, 0, 0, 1677, 0, 0, + 1713, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, + 0, 0, 0, 0, 0, 0, 1713, 0, 0, 0, + 0, 1713, 0, 1685, 0, 0, 0, 0, 0, 0, + 0, 1700, 0, 1687, 0, 0, 0, 0, 2009, 0, + 1688, 0, 0, 3215, 3216, 0, 3219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 37, 0, 0, 0, 38, 0, 0, 0, 0, 0, - 0, 0, 1689, 0, 0, 1420, 1421, 568, 0, 1422, - 1423, 0, 568, 0, 1701, 39, 0, 1702, 1703, 1704, - 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 40, - 0, 2166, 41, 0, 0, 42, 0, 0, 568, 0, - 43, 0, 0, 0, 0, 0, 0, 2876, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 44, 0, 568, - 568, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1424, 1425, 0, 1689, 1701, 0, + 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, + 1710, 0, 3242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 45, 0, 0, 568, 0, 1424, 1425, 0, 1713, - 0, 0, 0, 0, 0, 46, 0, 0, -48, 0, - 1690, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, - 1680, 1681, 0, 1682, 1683, 1684, 0, 1691, 0, 0, - 0, 0, 1692, 0, 0, 0, 0, 0, 0, 568, - 1685, 0, 0, 0, 0, 0, 0, 2160, 1713, 0, - 1687, 0, 0, 0, 0, 1693, 1694, 1688, 0, 0, - 0, 0, 0, 1426, 1427, 1428, 1429, 1430, 1431, 1432, - 1433, 1695, 0, 1434, 1435, 0, 0, 0, 0, 0, - 0, 0, 0, 1472, 1689, 0, 2953, 0, 0, 0, - 0, 0, 1676, 2955, 2126, 1677, 0, 0, 0, 1678, - 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 2964, - 0, 1696, 0, 0, 1697, 0, 0, 0, 0, 0, - 0, 1685, 2976, 0, 0, 2979, 0, 2981, 1698, 0, - 0, 1687, 0, 0, 0, 2985, 0, 0, 1688, 0, - 0, 0, 1713, 2992, 2993, 0, 0, 0, 1436, 1437, - 3000, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1689, 0, 3014, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3030, 0, - 0, 0, 1690, 0, 0, 0, 0, 0, 1713, 1438, - 1439, 0, 0, 0, 0, 1713, 0, 0, 1143, 1691, - 0, 0, 0, 0, 1692, 1676, 0, 0, 1677, 0, - 0, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, - 0, 0, 0, 0, 0, 0, 0, 1693, 1694, 0, - 0, 1700, 0, 0, 1685, 0, 0, 0, 0, 0, - 568, 0, 0, 1695, 1687, 0, 1713, 0, 0, 0, - 1759, 1688, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1690, 2395, 2395, 0, 0, 0, 0, - 1713, 0, 0, 0, 0, 0, 0, 3175, 1689, 0, - 1691, 0, 0, 1696, 0, 1692, 1697, 0, 0, 1440, - 1441, 0, 0, 0, 0, 0, 3189, 0, 0, 0, - 1698, 0, 0, 1699, 0, 0, 0, 0, 1693, 1694, - 0, 0, 0, 1442, 1443, 0, 0, 0, 1713, 0, - 1713, 0, 1472, 1472, 1695, 2009, 0, 0, 1472, 0, - 0, 1713, 0, 2090, 1713, 0, 0, 0, 0, 1713, - 0, 0, 1713, 1701, 0, 0, 1702, 1703, 1704, 0, + 0, 0, 3251, 0, 0, 0, 0, 3254, 3255, 0, + 0, 0, 3256, 0, 0, 0, 0, 3259, 0, 0, + 3262, 3263, 0, 0, 0, 2398, 1332, 0, 0, 3271, + 0, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 0, + 0, 1434, 1435, 1701, 0, 1143, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 0, 0, - 0, 0, 0, 0, 1696, 0, 0, 1697, 0, 0, - 0, 3250, 3251, 0, 3254, 0, 1690, 0, 0, 0, - 0, 1698, 0, 0, 1699, 0, 1713, 0, 0, 0, - 0, 0, 0, 1691, 0, 0, 0, 0, 1692, 0, - 0, 0, 0, 1700, 0, 0, 0, 0, 3275, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1693, 1694, 0, 0, 0, 0, 0, 3284, 0, - 0, 0, 0, 3287, 3288, 0, 0, 1695, 3289, 0, - 0, 0, 0, 3292, 0, 0, 3295, 3296, 0, 0, - 0, 2395, 1332, 0, 0, 3304, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1143, 0, 1713, 0, 0, 0, 1696, 0, 0, - 1697, 0, 0, 0, 1700, 0, 0, 0, 0, 0, - 1713, 0, 0, 0, 1698, 0, 0, 1699, 0, 0, - 0, 1713, 1713, 1713, 0, 0, 0, 0, 1713, 0, - 0, 0, 1713, 0, 0, 1701, 0, 3352, 1702, 1703, - 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, - 0, 0, 2529, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3371, 0, 0, 0, 0, 0, + 2967, 0, 0, 0, 0, 1690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1691, 0, 0, 0, 0, 1692, 0, 0, + 0, 3319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1713, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1701, 1700, 0, 1702, - 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 1676, - 0, 0, 1677, 2633, 0, 1713, 1678, 1679, 1680, 1681, - 0, 1682, 1683, 1684, 0, 0, 0, 0, 0, 0, - 0, 1713, 0, 0, 0, 0, 1713, 0, 1685, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1687, 0, - 0, 0, 0, 2009, 0, 1688, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3428, 3429, 0, 2876, 0, 0, 0, 0, 0, 0, - 0, 0, 1689, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1656, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1701, - 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, - 1709, 1710, 1676, 0, 0, 1677, 2647, 0, 0, 1678, - 1679, 1680, 1681, 2654, 1682, 1683, 1684, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3471, - 3472, 1685, 0, 3473, 0, 1647, 0, 0, 0, 0, - 0, 1687, 0, 0, 0, 0, 0, 0, 1688, 0, + 1693, 1694, 0, 0, 0, 0, 1436, 1437, 3338, 0, + 0, 0, 1713, 0, 0, 0, 1695, 0, 0, 0, + 2009, 2009, 0, 1472, 1472, 1472, 1472, 1472, 1472, 0, + 0, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, + 1472, 2009, 0, 0, 0, 0, 0, 1438, 1439, 0, + 0, 0, 0, 0, 0, 0, 1696, 0, 0, 1697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1690, 0, 0, 0, 0, 0, 0, 3497, 0, 0, - 0, 0, 0, 0, 0, 1689, 0, 1691, 0, 0, - 0, 0, 1692, 0, 0, 0, 0, 0, 0, 0, - 0, 3509, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1693, 1694, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1713, 0, 0, - 0, 1695, 0, 0, 0, 2009, 2009, 0, 1472, 1472, - 1472, 1472, 1472, 1472, 0, 0, 1472, 1472, 1472, 1472, - 1472, 1472, 1472, 1472, 1472, 1472, 2009, 0, 0, 0, + 0, 0, 0, 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1696, 0, 0, 1697, 0, 0, 0, 0, 0, - 0, 0, 0, 1690, 0, 0, 0, 0, 1698, 0, - 0, 1699, 0, 3250, 0, 0, 0, 3571, 0, 0, - 1691, 1143, 0, 0, 0, 1692, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3581, 0, 0, 0, 0, - 2395, 2395, 0, 0, 0, 0, 0, 0, 1693, 1694, - 0, 0, 1143, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1695, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3609, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1713, 0, - 0, 0, 1713, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1696, 0, 0, 1697, 0, 0, - 0, 1700, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1698, 3634, 1713, 1699, 0, 0, 0, 0, 0, - 0, 0, 3250, 0, 0, 0, 0, 1713, 0, 0, - 0, 0, 1713, 0, 1143, 0, 1713, 1713, 1713, 1713, - 1713, 1713, 1713, 1713, 0, 0, 0, 0, 0, 1472, - 1472, 3661, 1713, 1713, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1713, 0, 0, 1713, - 3681, 0, 0, 0, 0, 0, 0, 1713, 1713, 1713, - 1713, 1713, 1713, 1713, 1713, 1713, 1713, 0, 0, 0, + 0, 0, 3392, 3393, 0, 2881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1713, 1701, 1700, 0, 1702, 1703, 1704, 0, - 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 0, 0, - 2665, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, - 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 0, 0, - 0, 3744, 3744, 3744, 0, 1472, 0, 0, 0, 0, - 1685, 0, 3755, 0, 0, 0, 0, 0, 0, 0, - 1687, 0, 0, 0, 0, 0, 0, 1688, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 3744, 0, 0, + 1656, 0, 0, 1676, 0, 0, 1677, 0, 0, 0, + 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1440, 1441, 0, + 0, 0, 1685, 0, 0, 1713, 0, 2657, 0, 1713, + 0, 0, 1687, 0, 0, 0, 0, 0, 0, 1688, + 0, 1442, 1443, 3436, 3437, 0, 1700, 3438, 0, 1647, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1689, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1701, 0, 0, 1702, - 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, - 0, 0, 0, 2893, 0, 0, 0, 0, 0, 0, - 0, 1713, 0, 0, 0, 0, 3744, 0, 0, 0, - 0, 0, 1713, 1713, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1676, 0, 0, - 1677, 0, 0, 0, 1678, 1679, 1680, 1681, 0, 1682, - 1683, 1684, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1685, 0, 0, 0, - 0, 0, 1690, 0, 0, 0, 1687, 0, 0, 0, - 0, 0, 0, 1688, 0, 0, 0, 0, 0, 1691, - 0, 0, 0, 0, 1692, 0, 0, 0, 0, 0, + 1713, 0, 0, 0, 0, 0, 1689, 0, 0, 0, + 0, 0, 0, 0, 1713, 0, 0, 0, 0, 1713, + 0, 3462, 0, 1713, 1713, 1713, 1713, 1713, 1713, 1713, + 1713, 0, 0, 0, 0, 0, 1472, 1472, 0, 1713, + 1713, 0, 0, 0, 0, 3474, 0, 0, 0, 0, + 0, 0, 0, 1713, 0, 0, 1713, 0, 0, 0, + 0, 0, 0, 0, 1713, 1713, 1713, 1713, 1713, 1713, + 1713, 1713, 1713, 1713, 1676, 0, 0, 1677, 0, 0, + 0, 1678, 1679, 0, 0, 0, 1682, 1683, 1684, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1701, 1713, + 0, 1702, 1703, 1704, 1690, 1705, 1706, 1707, 1708, 1709, + 1710, 0, 0, 1687, 0, 2980, 0, 0, 0, 0, + 1688, 1691, 0, 0, 0, 0, 1692, 0, 0, 0, + 0, 0, 0, 0, 3215, 0, 0, 0, 3587, 0, + 0, 0, 1143, 0, 0, 0, 0, 1689, 0, 1693, + 1694, 0, 1472, 0, 0, 0, 0, 3597, 0, 0, + 0, 0, 2398, 2398, 0, 1695, 0, 0, 0, 0, + 0, 0, 0, 0, 1143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1689, 0, 0, 0, 0, 0, 0, 1693, 1694, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1713, 0, - 1713, 0, 0, 1695, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1713, 1713, 1713, 0, - 0, 2009, 2009, 2009, 2009, 2009, 2009, 0, 0, 0, - 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, - 0, 0, 0, 1696, 1713, 1713, 1697, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3625, 0, 0, 0, + 0, 0, 0, 0, 0, 1696, 0, 0, 1697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, - 1713, 0, 0, 0, 1676, 0, 0, 1677, 1690, 0, - 1713, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, - 0, 0, 0, 0, 0, 1691, 0, 0, 0, 0, - 1692, 0, 0, 1685, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1687, 0, 1713, 0, 0, 0, 0, - 1688, 0, 1713, 1693, 1694, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1713, 0, 0, 0, 0, 1695, - 1713, 0, 0, 0, 0, 1713, 1713, 1689, 0, 0, - 0, 0, 0, 2009, 2009, 0, 0, 0, 0, 0, - 0, 0, 0, 1700, 0, 0, 0, 1713, 1472, 1472, - 1713, 0, 1713, 0, 0, 0, 1713, 0, 0, 1696, - 1676, 0, 1697, 1677, 0, 0, 0, 1678, 1679, 1680, - 1681, 0, 1682, 1683, 1684, 0, 1698, 0, 0, 1699, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1685, - 0, 0, 0, 0, 0, 1676, 0, 0, 1677, 1687, - 0, 0, 1678, 1679, 1680, 1681, 1688, 1682, 1683, 1684, + 0, 0, 1698, 0, 0, 1699, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1713, + 0, 0, 0, 0, 0, 1690, 1676, 0, 0, 1677, + 1713, 1713, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, + 1684, 0, 1691, 0, 0, 0, 0, 1692, 0, 0, + 0, 0, 0, 0, 0, 1685, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1687, 0, 0, 0, 0, + -2193, -2193, 1688, 0, 0, 3654, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3215, 1695, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1143, 0, 1689, + 0, 0, 0, 0, 0, 1700, 0, 0, 0, 0, + 0, 0, 0, 0, 3681, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -2193, + 0, 0, 0, 3701, 1713, 0, 1713, 0, 0, 0, + 0, 0, 0, 1698, 0, 0, 0, 0, 0, 0, + 0, 0, 1713, 1713, 1713, 0, 0, 2009, 2009, 2009, + 2009, 2009, 2009, 0, 0, 0, 2009, 2009, 2009, 2009, + 2009, 2009, 2009, 2009, 2009, 2009, 0, 0, 0, 0, + 1713, 1713, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1690, 0, 0, 0, 0, 0, 0, 0, 0, 1713, 0, 0, 0, - 0, 0, 0, 0, 1685, 1690, 0, 0, 0, 0, - 0, 0, 0, 1689, 1687, 0, 0, 0, 0, 0, - 0, 1688, 1691, 0, 0, 0, 0, 1692, 0, 0, - 0, 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, - 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 1689, 0, - 1693, 1694, 2960, 0, 0, 0, 0, 0, 0, 1700, - 0, 0, 0, 0, 0, 0, 1695, 0, 0, 0, + 0, 0, 0, 0, 1691, 0, 1713, 1701, 0, 1692, + 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, + 3769, 3769, 3769, 0, 3054, 0, 0, 0, 0, 0, + 0, 3780, 1693, 1694, 0, 0, 1700, 0, 0, 0, + 0, 0, 0, 1713, 0, 0, 0, 0, 1695, 0, + 1713, 0, 0, 0, 0, 0, 0, 0, 0, 3769, + 0, 0, 1713, 0, 0, 0, 0, 0, 1713, 0, + 0, 0, 0, 1713, 1713, 0, 0, 0, 0, 0, + 0, 2009, 2009, 0, 0, 0, 0, 0, 1696, 0, + 0, 1697, 0, 0, 0, 1713, 1472, 1472, 1713, 0, + 1713, 0, 0, 0, 1713, 1698, 0, 0, 1699, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, - 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1696, 0, 0, 1697, - 1685, 1690, 0, 0, 0, 0, 0, 0, 0, 0, - 1687, 0, 1713, 1698, 0, 0, 1699, 1688, 1691, 0, - 0, 0, 0, 1692, 0, 0, 0, 0, 0, 0, - 0, 1472, 0, 0, 0, 0, 1690, 0, 0, 0, - 0, 0, 0, 0, 1689, 0, 1693, 1694, 0, 0, - 0, 0, 0, 1691, 0, 0, 0, 0, 1692, 0, - 0, 1701, 1695, 0, 1702, 1703, 1704, 0, 1705, 1706, - 1707, 1708, 1709, 1710, 0, 0, 0, 0, 2973, 0, - 0, 1693, 1694, 0, 0, 0, 0, 0, 0, 1713, - 0, 1713, 0, 0, 0, 0, 0, 1695, 0, 0, - 1713, 0, 1696, 0, 0, 1697, 0, 0, 0, 0, - 0, 0, 1713, 0, 0, 1713, 1700, 1713, 0, 1698, - 0, 1713, 1699, 0, 2009, 2009, 0, 0, 1713, 1713, - 0, 0, 0, 0, 0, 0, 1713, 1696, 0, 0, - 1697, 0, 1690, 0, 0, 0, 0, 0, 0, 0, - 1713, 0, 0, 0, 1698, 0, 0, 1699, 0, 1691, - 0, 0, 0, 0, 1692, 0, 1713, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1676, 0, 0, - 1677, 0, 0, 0, 1678, 1679, 0, 1693, 1694, 1682, - 1683, 1684, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1695, 0, 1472, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1687, 0, 0, 0, - 0, 0, 1700, 1688, 0, 0, 0, 0, 1701, 0, + 0, 0, 0, 1676, 0, 0, 1677, 0, 0, 0, + 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, - 1710, 0, 0, 1696, 0, 3047, 1697, 0, 0, 0, - 1689, 0, 0, 0, 0, 0, 0, 1700, 0, 0, - 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, + 1710, 0, 1685, 0, 1713, 0, 0, 0, 0, 0, + 0, 0, 1687, 0, 0, 0, 0, 0, 0, 1688, 0, 0, 0, 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1689, 0, 1700, 0, 0, 0, 0, 1685, 0, 0, 0, 0, 0, 0, - 0, 1713, 0, 1687, 0, 0, 0, 0, 0, 0, - 1688, 0, 0, 0, 0, 1713, 0, 0, 0, 0, - 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, 1704, - 0, 1705, 1706, 1707, 1708, 1709, 1710, 1689, 1690, 0, - 0, 3298, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2009, 1472, 1700, 0, 1691, 0, 0, 0, 1701, - 1692, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, - 1709, 1710, 0, 0, 1876, 0, 1713, 1713, 0, 0, - 1713, 0, 0, -2183, -2183, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1695, - 0, 1713, 0, 0, 0, 0, 0, 0, 0, 0, - 1713, 0, 0, 1713, 1713, 1713, 0, 0, 1713, 0, - 0, 1713, 1713, 0, 0, 0, 0, 0, 0, 0, - 1713, 0, 0, 0, 0, 1690, 0, 0, 0, 0, - 0, 0, -2183, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1691, 0, 0, 0, 1698, 1692, 0, 0, - 0, 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, - 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 1713, 0, - 1693, 1694, 3305, 0, 2009, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1695, 1713, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1696, 0, 0, 1697, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1698, 1713, 1713, 1699, 0, 0, 1700, - 0, 2009, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1687, 0, 0, 0, 0, 0, 0, + 1688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1689, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1676, + 0, 0, 1677, 0, 0, 0, 1678, 1679, 1680, 1681, + 0, 1682, 1683, 1684, 0, 0, 0, 0, 0, 0, + 0, 0, 1713, 0, 0, 0, 0, 0, 1685, 0, + 0, 0, 0, 0, 1690, 0, 0, 0, 1687, 0, + 0, 1472, 0, 0, 0, 1688, 0, 0, 0, 0, + 1701, 1691, 0, 1702, 1703, 1704, 1692, 1705, 1706, 1707, + 1708, 1709, 1710, 0, 0, 0, 0, 3265, 0, 0, + 0, 0, 1689, 0, 0, 0, 0, 0, 0, 1693, + 1694, 0, 0, 0, 0, 1690, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1695, 0, 0, 0, 0, + 0, 1713, 1691, 1713, 0, 0, 0, 1692, 0, 0, + 0, 0, 1713, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1713, 0, 0, 1713, 0, 1713, + 1693, 1694, 0, 1713, 0, 1696, 2009, 2009, 1697, 0, + 1713, 1713, 0, 0, 0, 0, 1695, 0, 1713, 0, + 0, 0, 1698, 0, 0, 1699, 0, 0, 0, 0, + 0, 0, 1713, 0, 0, 0, 0, 0, 0, 0, + 1690, 0, 0, 0, 0, 0, 0, 0, 1713, 0, + 0, 0, 0, 0, 0, 0, 1696, 1691, 0, 1697, + 0, 0, 1692, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1698, 0, 0, 1699, 0, 0, 0, + 0, 0, 0, 0, 0, 1693, 1694, 1472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1713, 1713, 1713, + 0, 1695, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1713, + 1713, 0, 0, 0, 0, 1700, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1676, + 0, 1696, 1677, 0, 1697, 1713, 1678, 1679, 1680, 1681, + 0, 1682, 1683, 1684, 0, 0, 0, 0, 1698, 1713, + 0, 1699, 0, 0, 0, 0, 0, 0, 1685, 0, + 0, 0, 0, 0, 0, 0, 1700, 0, 1687, 0, + 0, 0, 0, 0, 0, 1688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2009, 1472, 0, 0, 0, 0, 0, 0, 0, + 0, 735, 1689, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1713, 1713, 0, 0, + 1713, 0, 0, 0, 0, 0, 0, 1701, 0, 0, + 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, + 0, 0, 0, 1713, 3272, 0, 0, 0, 0, 0, + 0, 1700, 1713, 0, 0, 1713, 1713, 1713, 736, 0, + 1713, 0, 0, 1713, 1713, 1418, 1419, 0, 0, 0, + 0, 0, 1713, 0, 737, 0, 0, 0, 1701, 0, + 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, + 1710, 0, 0, 0, 0, 3359, 0, 0, 0, 0, + 1690, 0, 0, 0, 0, 0, 1420, 1421, 0, 0, + 1422, 1423, 0, 0, 0, 0, 0, 1691, 0, 0, + 1713, 0, 1692, 0, 738, 0, 2009, 0, 0, 0, + 0, 0, 0, 0, 739, 0, 0, 0, 0, 1713, + 0, 0, 0, 0, 0, 1693, 1694, 740, 0, 0, + 0, 0, 741, 0, 0, 0, 0, 0, 0, 0, + 0, 1695, 0, 1701, 0, 0, 1702, 1703, 1704, 0, + 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 0, 0, + 3443, 742, 0, 0, 0, 0, 0, 1424, 1425, 0, + 0, 0, 0, 1713, 1713, 0, 0, 0, 0, 0, + 2009, 1696, 0, 0, 1697, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1698, 0, + 0, 1699, 0, 0, 0, 743, 0, 0, 0, 0, + 744, 0, 0, 0, 0, 0, 0, 1713, 1713, 1713, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1713, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1426, 1427, 1428, 1429, 1430, 1431, + 1432, 1433, 0, 1713, 1434, 1435, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1713, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1700, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, - 1707, 1708, 1709, 1710, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1713, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1713, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, + 0, 0, 745, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 746, 0, 0, + 0, 1700, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1436, + 1437, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 747, 0, 0, 748, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 749, 0, 0, 750, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1713, 0, 0, 0, 0, + 1438, 1439, 0, 0, 0, 0, 0, 0, 1713, 751, + 0, 0, 0, 0, 0, 0, 0, 0, 1713, 0, + 0, 0, 0, 752, 0, 0, 0, 0, 0, 0, + 753, 754, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 755, 0, 0, 0, 0, 1713, 756, 0, 0, + 0, 0, 0, 1701, 0, 0, 1702, 1703, 1704, 0, + 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 0, 0, + 3471, 0, 0, 0, 0, 1713, 757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1713, 0, 0, 0, 0, 0, 0, 0, 1701, 0, - 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, - 1710, 0, 0, 0, 0, 3395, 0, 1713, 0, 0, + 1440, 1441, 1713, 0, 0, 0, 0, 0, 0, 0, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1713, 0, 0, + 0, 0, 1713, 0, 1442, 1443, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, - 131, 132, 0, 0, 0, 0, 0, 1082, 0, 0, + 131, 132, 0, 0, 2092, 0, 0, 1082, 0, 0, 133, 134, 135, 0, 136, 137, 138, 139, 140, 141, 142, 143, 1083, 145, 1084, 1085, 0, 0, 148, 149, 150, 151, 152, 1086, 805, 153, 154, 155, 156, 1087, @@ -5699,7 +5704,7 @@ static const yytype_int16 yytable[] = 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 45, 0, 0, 0, 0, 1119, 1120, 1121, 0, - 0, 0, 0, 1122, 0, 1123, 3446, 0, 0, 0, + 0, 0, 0, 1122, 0, 1123, 3410, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, @@ -5961,7 +5966,7 @@ static const yytype_int16 yytable[] = 474, 816, 476, 817, 1115, 478, 479, 1326, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, 1327, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, - 498, 1117, 500, 2403, 501, 1329, 503, 504, 505, 506, + 498, 1117, 500, 2406, 501, 1329, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, @@ -6071,7 +6076,7 @@ static const yytype_int16 yytable[] = 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 0, 0, 0, 0, 0, 1119, 1120, 1121, 0, 0, 0, - 0, 1122, 0, 1123, 3301, 0, 0, 0, 1124, 1125, + 0, 1122, 0, 1123, 3268, 0, 0, 0, 1124, 1125, 1126, 1127, 1291, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, @@ -6128,8 +6133,8 @@ static const yytype_int16 yytable[] = 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, - 126, 127, 128, 129, -1196, 130, 131, 132, 0, 0, - 0, 0, -1196, 1082, 0, 0, 133, 134, 135, 0, + 126, 127, 128, 129, -1206, 130, 131, 132, 0, 0, + 0, 0, -1206, 1082, 0, 0, 133, 134, 135, 0, 136, 137, 138, 139, 140, 141, 142, 143, 1083, 145, 1084, 1085, 0, 0, 148, 149, 150, 151, 152, 1086, 805, 153, 154, 155, 156, 1087, 1088, 159, 0, 160, @@ -6165,7 +6170,7 @@ static const yytype_int16 yytable[] = 0, 409, 410, 411, 412, 413, 414, 1111, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, 435, - 436, 437, 0, 438, 439, 440, 1112, 442, -1196, 443, + 436, 437, 0, 438, 439, 440, 1112, 442, -1206, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 815, 0, 0, 460, 461, 0, 462, 463, 464, 465, 466, 467, 468, 469, 0, @@ -6391,10 +6396,10 @@ static const yytype_int16 yytable[] = 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 0, 0, 0, 0, 0, 1119, 1120, - 1121, 0, 0, 0, 0, 1122, 0, 1123, 2151, 0, + 1121, 0, 0, 0, 0, 1122, 0, 1123, 2153, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, - 0, 0, 2808, 0, 0, 0, 122, 123, 124, 125, + 0, 0, 2812, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 1082, 0, 0, 133, 134, 135, 0, 136, 137, 138, 139, 140, 141, 142, 143, 1083, 145, @@ -6488,7 +6493,7 @@ static const yytype_int16 yytable[] = 432, 433, 434, 435, 436, 437, 0, 438, 439, 440, 1112, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 815, - 0, 0, 460, 461, 2875, 462, 463, 464, 465, 466, + 0, 0, 460, 461, 2880, 462, 463, 464, 465, 466, 467, 468, 469, 0, 470, 1113, 1114, 0, 0, 473, 474, 816, 476, 817, 1115, 478, 479, 818, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, 1116, 0, @@ -6547,7 +6552,7 @@ static const yytype_int16 yytable[] = 479, 818, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, 1116, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, 1117, 500, 0, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 0, 2999, 510, + 503, 504, 505, 506, 507, 508, 509, 0, 3006, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 0, 0, 0, 0, 0, @@ -6555,14 +6560,14 @@ static const yytype_int16 yytable[] = 0, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, - 124, 125, 126, 127, 128, 129, 3238, 130, 131, 132, + 124, 125, 126, 127, 128, 129, 3203, 130, 131, 132, 0, 0, 0, 0, 0, 1082, 0, 0, 133, 134, 135, 0, 136, 137, 138, 139, 140, 141, 142, 143, 1083, 145, 1084, 1085, 0, 0, 148, 149, 150, 151, 152, 1086, 805, 153, 154, 155, 156, 1087, 1088, 159, 0, 160, 161, 162, 163, 806, 0, 807, 0, 1089, 167, 168, 169, 170, 171, 172, 173, 174, 175, 0, - 176, 177, 178, 179, 180, 181, 0, 182, 183, 3239, + 176, 177, 178, 179, 180, 181, 0, 182, 183, 3204, 185, 186, 187, 188, 189, 190, 191, 192, 1090, 194, 195, 1091, 197, 1092, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, @@ -6570,7 +6575,7 @@ static const yytype_int16 yytable[] = 217, 218, 219, 220, 0, 221, 222, 223, 224, 1094, 226, 227, 228, 229, 230, 231, 808, 1095, 233, 0, 234, 235, 1096, 237, 0, 238, 0, 239, 240, 0, - 241, 242, 243, 244, 245, 246, 247, 248, 0, 3240, + 241, 242, 243, 244, 245, 246, 247, 248, 0, 3205, 1098, 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 273, 274, 275, 276, @@ -6589,7 +6594,7 @@ static const yytype_int16 yytable[] = 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, 1110, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 0, 409, 410, 411, 412, 413, 3241, 1111, + 407, 408, 0, 409, 410, 411, 412, 413, 3206, 1111, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, 437, 0, 438, 439, 440, 1112, 442, @@ -6605,9 +6610,9 @@ static const yytype_int16 yytable[] = 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 0, 0, 0, 0, 0, 1119, 1120, 1121, 0, 0, 0, - 0, 1122, 0, 3242, 0, 0, 0, 0, 1124, 1125, + 0, 1122, 0, 3207, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, - 0, 0, 0, 0, 0, 0, 0, 0, 3474, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3439, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 1082, 0, 0, 133, 134, 135, 0, 136, 137, 138, 139, @@ -6766,7 +6771,7 @@ static const yytype_int16 yytable[] = 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 0, 0, 0, 0, 0, 1776, 1777, 1121, 0, 0, 0, 0, 1122, 0, 1123, 0, 0, 0, 0, - 1124, 1125, 1126, 1127, 121, 2294, 836, 1077, 1078, 1079, + 1124, 1125, 1126, 1127, 121, 2296, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, @@ -6871,7 +6876,7 @@ static const yytype_int16 yytable[] = 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 0, - 0, 0, 0, 0, 1119, 2394, 1121, 0, 0, 0, + 0, 0, 0, 0, 1119, 2397, 1121, 0, 0, 0, 0, 1122, 0, 1123, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -6925,7 +6930,7 @@ static const yytype_int16 yytable[] = 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 0, 0, 0, 0, 0, 1119, 1120, - 1121, 0, 0, 0, 0, 1122, 0, 2653, 0, 0, + 1121, 0, 0, 0, 0, 1122, 0, 2656, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, @@ -6978,7 +6983,7 @@ static const yytype_int16 yytable[] = 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 0, 0, 0, - 0, 0, 1119, 3299, 1121, 0, 0, 0, 0, 1122, + 0, 0, 1119, 3266, 1121, 0, 0, 0, 0, 1122, 0, 1123, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -6990,7 +6995,7 @@ static const yytype_int16 yytable[] = 1088, 159, 0, 160, 161, 162, 163, 806, 0, 807, 0, 1089, 167, 168, 169, 170, 171, 172, 173, 174, 175, 0, 176, 177, 178, 179, 180, 181, 0, 182, - 183, 3239, 185, 186, 187, 188, 189, 190, 191, 192, + 183, 3204, 185, 186, 187, 188, 189, 190, 191, 192, 1090, 194, 195, 1091, 197, 1092, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 1093, 212, 213, 0, 214, 215, @@ -6998,7 +7003,7 @@ static const yytype_int16 yytable[] = 224, 1094, 226, 227, 228, 229, 230, 231, 808, 1095, 233, 0, 234, 235, 1096, 237, 0, 238, 0, 239, 240, 0, 241, 242, 243, 244, 245, 246, 247, 248, - 0, 3240, 1098, 251, 252, 0, 253, 254, 255, 256, + 0, 3205, 1098, 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 273, 274, 275, 276, 277, 278, 279, 1099, 1100, 0, 1101, 0, @@ -7017,7 +7022,7 @@ static const yytype_int16 yytable[] = 386, 387, 388, 389, 390, 1110, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, 411, 412, 413, - 3241, 1111, 416, 417, 418, 419, 420, 421, 422, 423, + 3206, 1111, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, 437, 0, 438, 439, 440, 1112, 442, 0, 443, 444, 445, 446, 447, 448, 449, @@ -7032,18 +7037,18 @@ static const yytype_int16 yytable[] = 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1118, 0, 0, 0, 0, 0, 0, 1119, 1120, 1121, 0, - 0, 0, 0, 1122, 0, 3242, 0, 0, 0, 0, + 0, 0, 0, 1122, 0, 3207, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 1082, 0, 0, 133, 134, 135, 0, 136, 137, - 138, 139, 140, 141, 142, 3741, 1083, 145, 1084, 1085, + 138, 139, 140, 141, 142, 3766, 1083, 145, 1084, 1085, 0, 0, 148, 149, 150, 151, 152, 1086, 805, 153, 154, 155, 156, 1087, 1088, 159, 0, 160, 161, 162, 163, 806, 0, 807, 0, 1089, 167, 168, 169, 170, 171, 172, 173, 174, 175, 0, 176, 177, 178, 179, - 180, 181, 0, 182, 183, 184, 3742, 186, 187, 188, + 180, 181, 0, 182, 183, 184, 3767, 186, 187, 188, 189, 190, 191, 192, 1090, 194, 195, 1091, 197, 1092, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 1093, 212, @@ -7078,7 +7083,7 @@ static const yytype_int16 yytable[] = 456, 457, 458, 815, 0, 0, 460, 461, 0, 462, 463, 464, 465, 466, 467, 468, 469, 0, 470, 1113, 1114, 0, 0, 473, 474, 816, 476, 817, 1115, 478, - 479, 818, 481, 482, 3743, 484, 485, 0, 0, 486, + 479, 818, 481, 482, 3768, 484, 485, 0, 0, 486, 487, 488, 1116, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, 1117, 500, 0, 501, 502, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, @@ -7097,7 +7102,7 @@ static const yytype_int16 yytable[] = 0, 160, 161, 162, 163, 806, 0, 807, 0, 1089, 167, 168, 169, 170, 171, 172, 173, 174, 175, 0, 176, 177, 178, 179, 180, 181, 0, 182, 183, 184, - 3742, 186, 187, 188, 189, 190, 191, 192, 1090, 194, + 3767, 186, 187, 188, 189, 190, 191, 192, 1090, 194, 195, 1091, 197, 1092, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 1093, 212, 213, 0, 214, 215, 216, 0, @@ -7131,7 +7136,7 @@ static const yytype_int16 yytable[] = 452, 453, 454, 455, 456, 457, 458, 815, 0, 0, 460, 461, 0, 462, 463, 464, 465, 466, 467, 468, 469, 0, 470, 1113, 1114, 0, 0, 473, 474, 816, - 476, 817, 1115, 478, 479, 818, 481, 482, 3743, 484, + 476, 817, 1115, 478, 479, 818, 481, 482, 3768, 484, 485, 0, 0, 486, 487, 488, 1116, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, 1117, 500, 0, 501, 502, 503, 504, 505, 506, 507, 508, @@ -7145,25 +7150,25 @@ static const yytype_int16 yytable[] = 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 1082, 0, 0, 133, 134, 135, 0, 136, 137, 138, 139, - 140, 141, 142, -2183, 1083, 145, 1084, 1085, 0, 0, + 140, 141, 142, -2193, 1083, 145, 1084, 1085, 0, 0, 148, 149, 150, 151, 152, 1086, 805, 153, 154, 155, 156, 1087, 1088, 159, 0, 160, 161, 162, 163, 806, 0, 807, 0, 1089, 167, 168, 169, 170, 171, 172, 173, 174, 175, 0, 176, 177, 178, 179, 180, 181, - 0, 182, 183, 184, 3742, 186, 187, 188, 189, 190, + 0, 182, 183, 184, 3767, 186, 187, 188, 189, 190, 191, 192, 1090, 194, 195, 1091, 197, 1092, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 1093, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, 222, 223, 224, 1094, 226, 227, 228, 229, 230, 231, 808, 1095, 233, 0, 234, 235, 1096, 237, 0, 238, - 0, 239, 240, 0, 241, 242, 243, 244, -2183, 246, + 0, 239, 240, 0, 241, 242, 243, 244, -2193, 246, 247, 248, 0, 1097, 1098, 251, 252, 0, 253, 254, - 255, 256, 257, 258, 259, -2183, 261, 262, 263, 264, + 255, 256, 257, 258, 259, -2193, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 273, 274, 275, 276, 277, 278, 279, 1099, 1100, 0, 1101, 0, 283, 0, 0, 286, 287, 288, 289, 290, - 1102, 291, 292, 293, 0, 0, 294, 295, 296, -2183, + 1102, 291, 292, 293, 0, 0, 294, 295, 296, -2193, 0, 298, 299, 300, 301, 302, 303, 304, 305, 1103, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, @@ -7179,19 +7184,19 @@ static const yytype_int16 yytable[] = 403, 404, 405, 406, 407, 408, 0, 409, 410, 411, 412, 413, 414, 1111, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, - 430, 431, 432, 433, 434, 435, 436, 437, 0, -2183, + 430, 431, 432, 433, 434, 435, 436, 437, 0, -2193, 439, 440, 1112, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 815, 0, 0, 460, 461, 0, 462, 463, 464, 465, 466, 467, 468, 469, 0, 470, 1113, 1114, 0, 0, 473, 474, 816, 476, 817, 1115, 478, 479, 818, - 481, 482, 3743, 484, 485, 0, 0, 486, 487, 488, + 481, 482, 3768, 484, 485, 0, 0, 486, 487, 488, 1116, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, 1117, 500, 0, 501, 502, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, - 531, -2183, 0, 0, 0, 0, 0, 0, 1119, 1120, + 531, -2193, 0, 0, 0, 0, 0, 0, 1119, 1120, 1121, 0, 0, 0, 0, 1122, 0, 1123, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, @@ -7284,7 +7289,7 @@ static const yytype_int16 yytable[] = 386, 387, 388, 389, 390, 1110, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, 411, 412, 413, - 414, 2280, 2281, 417, 418, 419, 420, 421, 422, 423, + 414, 2282, 2283, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, 437, 0, 438, 439, 440, 1112, 442, 0, 443, 444, 445, 446, 447, 448, 449, @@ -7298,7 +7303,7 @@ static const yytype_int16 yytable[] = 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 0, - 0, 0, 0, 0, 0, 0, 2282, 2283, 0, 0, + 0, 0, 0, 0, 0, 0, 2284, 2285, 0, 0, 0, 0, 0, 1122, 0, 1123, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 121, 1076, 836, 1077, 1078, 1079, 1080, 1081, 0, 0, 0, 0, 0, 0, 0, 0, @@ -7371,7 +7376,7 @@ static const yytype_int16 yytable[] = 217, 218, 219, 220, 0, 221, 222, 223, 224, 1094, 226, 227, 228, 229, 230, 231, 808, 1095, 233, 0, 234, 235, 1096, 237, 0, 238, 0, 239, 240, 0, - 241, 242, 243, 244, 245, 246, 247, 248, 3260, 1097, + 241, 242, 243, 244, 245, 246, 247, 248, 3225, 1097, 1098, 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 273, 274, 275, 276, @@ -7406,7 +7411,7 @@ static const yytype_int16 yytable[] = 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 0, 0, 0, 0, 0, 121, 1076, 836, 1077, 1078, 0, 1080, 1081, - 0, 1122, 0, 2922, 0, 0, 0, 0, 1124, 1125, + 0, 1122, 0, 2927, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 1082, 0, 0, 133, 134, 135, 0, 136, 137, 138, 139, @@ -7457,7 +7462,7 @@ static const yytype_int16 yytable[] = 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 0, 0, 0, 0, 0, 121, 1076, 836, 1077, - 1078, 0, 1080, 1081, 0, 1122, 0, 2922, 0, 0, + 1078, 0, 1080, 1081, 0, 1122, 0, 2927, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 1082, 0, 0, 133, 134, 135, 0, @@ -7611,7 +7616,7 @@ static const yytype_int16 yytable[] = 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 0, 0, 0, 0, 0, 539, 2032, - 0, 0, 0, 0, 2033, 1081, 0, 1122, 0, 2198, + 0, 0, 0, 0, 2033, 1081, 0, 1122, 0, 2200, 0, 0, 0, 0, 1124, 1125, 1126, 1127, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, @@ -7676,22 +7681,22 @@ static const yytype_int16 yytable[] = 193, 194, 195, 196, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, -585, 221, 222, 223, + 216, 0, 217, 218, 219, 220, -591, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 0, - 233, -585, 234, 235, 236, 237, -585, 238, 0, 239, + 233, -591, 234, 235, 236, 237, -591, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, - 275, 276, 277, 278, 279, 280, 281, -585, 282, 0, + 275, 276, 277, 278, 279, 280, 281, -591, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, - 292, 293, 0, 0, 294, 0, 296, 0, -585, 298, + 292, 293, 0, 0, 294, 0, 296, 0, -591, 298, 299, 300, 301, 302, 303, 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, 334, 335, 0, 336, 337, - 0, 339, 0, 340, 341, 342, 343, 344, 345, -585, - 346, 347, 0, 0, 348, 349, 350, 0, -585, 351, + 0, 339, 0, 340, 341, 342, 343, 344, 345, -591, + 346, 347, 0, 0, 348, 349, 350, 0, -591, 351, 352, 353, 0, 355, 0, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 0, 0, 0, 0, 370, 371, 372, 0, 374, 375, 376, 377, @@ -7707,7 +7712,7 @@ static const yytype_int16 yytable[] = 0, 0, 460, 461, 0, 462, 0, 464, 465, 466, 467, 468, 469, 0, 470, 471, 472, 0, 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, 481, 482, - 483, 484, 485, -585, 0, 486, 487, 488, 0, 0, + 483, 484, 485, -591, 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, @@ -7763,109 +7768,109 @@ static const yytype_int16 yytable[] = 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, - 524, 525, 526, 527, 528, 529, 530, 531, 2461, 0, + 524, 525, 526, 527, 528, 529, 530, 531, 2462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2599, 3460, 0, 0, 122, 123, + 0, 0, 0, 0, 2600, 3424, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, - 0, 0, 0, 1293, 0, 0, 0, 0, 2462, 134, - 135, 0, 2463, 137, 138, 2464, 140, 141, 142, 0, - 0, 2465, 0, 0, 0, 1298, 148, 149, 150, 151, + 0, 0, 0, 1293, 0, 0, 0, 0, 2463, 134, + 135, 0, 2464, 137, 138, 2465, 140, 141, 142, 0, + 0, 2466, 0, 0, 0, 1298, 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, 0, 0, 159, - 0, 160, 161, 162, 163, 0, 0, 2466, 0, 2467, - 167, 168, 169, 170, 171, 2468, 173, 174, 175, 0, - 176, 177, 178, 179, 180, 181, 0, 2469, 183, 184, + 0, 160, 161, 162, 163, 0, 0, 2467, 0, 2468, + 167, 168, 169, 170, 171, 2469, 173, 174, 175, 0, + 176, 177, 178, 179, 180, 181, 0, 2470, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 0, 194, 195, 0, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, 222, 223, 224, 0, 226, 227, 228, 229, 230, 231, 0, 0, 233, 0, - 234, 235, 0, 237, 0, 238, 0, 239, 2470, 0, - 2471, 242, 243, 2472, 2473, 246, 247, 248, 0, 0, + 234, 235, 0, 237, 0, 238, 0, 239, 2471, 0, + 2472, 242, 243, 2473, 2474, 246, 247, 248, 0, 0, 0, 251, 252, 0, 253, 254, 255, 256, 257, 258, - 259, 2474, 261, 262, 263, 264, 0, 265, 266, 267, - 268, 269, 270, 271, 0, 272, 2475, 0, 275, 276, - 277, 278, 279, 0, 0, 0, 0, 0, 283, 2476, - 2477, 286, 2478, 288, 289, 290, 0, 291, 292, 293, - 0, 0, 294, 2479, 296, 2480, 0, 298, 299, 300, - 301, 302, 303, 304, 305, 2481, 307, 308, 309, 310, + 259, 2475, 261, 262, 263, 264, 0, 265, 266, 267, + 268, 269, 270, 271, 0, 272, 2476, 0, 275, 276, + 277, 278, 279, 0, 0, 0, 0, 0, 283, 2477, + 2478, 286, 2479, 288, 289, 290, 0, 291, 292, 293, + 0, 0, 294, 2480, 296, 2481, 0, 298, 299, 300, + 301, 302, 303, 304, 305, 2482, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, 0, 2482, - 0, 332, 333, 334, 0, 0, 336, 337, 2483, 339, + 321, 322, 323, 324, 325, 326, 327, 328, 0, 2483, + 0, 332, 333, 334, 0, 0, 336, 337, 2484, 339, 0, 0, 341, 0, 343, 344, 345, 0, 346, 347, 0, 0, 348, 349, 350, 0, 0, 351, 352, 0, - 2484, 355, 2485, 0, 358, 359, 360, 361, 362, 363, + 2485, 355, 2486, 0, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 0, 0, 0, 0, - 370, 371, 0, 2486, 374, 375, 0, 377, 378, 379, + 370, 371, 0, 2487, 374, 375, 0, 377, 378, 379, 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, 0, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 0, 409, 410, 2487, 412, 413, 414, 0, + 407, 408, 0, 409, 410, 2488, 412, 413, 414, 0, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 1322, 429, 430, 431, 432, 433, - 434, 0, 436, 437, 0, 2488, 439, 440, 0, 442, + 434, 0, 436, 437, 0, 2489, 439, 440, 0, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, - 452, 453, 454, 455, 456, 2489, 458, 0, 0, 0, - 460, 461, 0, 462, 2490, 464, 465, 466, 467, 468, + 452, 453, 454, 455, 456, 2490, 458, 0, 0, 0, + 460, 461, 0, 462, 2491, 464, 465, 466, 467, 468, 469, 0, 470, 0, 0, 0, 0, 473, 474, 0, - 476, 0, 0, 478, 479, 2491, 481, 482, 483, 484, - 485, 0, 0, 486, 487, 488, 2492, 0, 489, 490, + 476, 0, 0, 478, 479, 2492, 481, 482, 483, 484, + 485, 0, 0, 486, 487, 488, 2493, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, 0, 0, - 500, 0, 501, 2493, 503, 504, 505, 506, 507, 508, + 500, 0, 501, 2494, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, - 515, 516, 2461, 0, 0, 0, 0, 0, 0, 0, + 515, 516, 2462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 528, 529, 530, 531, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, - 0, 130, 131, 132, 2494, 0, 0, 1293, 0, 0, - 0, 0, 2462, 134, 135, 0, 2463, 137, 138, 2464, - 140, 141, 142, 0, 0, 2465, 0, 0, 0, 1298, + 0, 130, 131, 132, 2495, 0, 0, 1293, 0, 0, + 0, 0, 2463, 134, 135, 0, 2464, 137, 138, 2465, + 140, 141, 142, 0, 0, 2466, 0, 0, 0, 1298, 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, 0, 0, 159, 0, 160, 161, 162, 163, 0, - 0, 2466, 0, 2467, 167, 168, 169, 170, 171, 2468, + 0, 2467, 0, 2468, 167, 168, 169, 170, 171, 2469, 173, 174, 175, 0, 176, 177, 178, 179, 180, 181, - 0, 2469, 183, 184, 185, 186, 187, 188, 189, 190, + 0, 2470, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 0, 194, 195, 0, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, 222, 223, 224, 0, 226, 227, 228, 229, 230, 231, 0, 0, 233, 0, 234, 235, 0, 237, 0, 238, - 0, 239, 2470, 0, 2471, 242, 243, 2472, 2473, 246, + 0, 239, 2471, 0, 2472, 242, 243, 2473, 2474, 246, 247, 248, 0, 0, 0, 251, 252, 0, 253, 254, - 255, 256, 257, 258, 259, 2474, 261, 262, 263, 264, + 255, 256, 257, 258, 259, 2475, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, - 2475, 0, 275, 276, 277, 278, 279, 0, 0, 0, - 0, 0, 283, 2476, 2477, 286, 2478, 288, 289, 290, - 0, 291, 292, 293, 0, 0, 294, 2479, 296, 2480, - 0, 298, 299, 300, 301, 302, 303, 304, 305, 2481, + 2476, 0, 275, 276, 277, 278, 279, 0, 0, 0, + 0, 0, 283, 2477, 2478, 286, 2479, 288, 289, 290, + 0, 291, 292, 293, 0, 0, 294, 2480, 296, 2481, + 0, 298, 299, 300, 301, 302, 303, 304, 305, 2482, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 0, 2482, 0, 332, 333, 334, 0, 0, - 336, 337, 2483, 339, 0, 0, 341, 0, 343, 344, + 327, 328, 0, 2483, 0, 332, 333, 334, 0, 0, + 336, 337, 2484, 339, 0, 0, 341, 0, 343, 344, 345, 0, 346, 347, 0, 0, 348, 349, 350, 0, - 0, 351, 352, 0, 2484, 355, 2485, 0, 358, 359, + 0, 351, 352, 0, 2485, 355, 2486, 0, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, - 0, 0, 0, 0, 370, 371, 0, 2486, 374, 375, + 0, 0, 0, 0, 370, 371, 0, 2487, 374, 375, 0, 377, 378, 379, 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, 0, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 0, 409, 410, 2487, + 403, 404, 405, 406, 407, 408, 0, 409, 410, 2488, 412, 413, 414, 0, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 1322, 429, - 430, 431, 432, 433, 434, 0, 436, 437, 0, 2488, + 430, 431, 432, 433, 434, 0, 436, 437, 0, 2489, 439, 440, 0, 442, 0, 443, 444, 445, 446, 447, - 448, 449, 450, 451, 452, 453, 454, 455, 456, 2489, - 458, 0, 0, 0, 460, 461, 0, 462, 2490, 464, + 448, 449, 450, 451, 452, 453, 454, 455, 456, 2490, + 458, 0, 0, 0, 460, 461, 0, 462, 2491, 464, 465, 466, 467, 468, 469, 0, 470, 0, 0, 0, - 0, 473, 474, 0, 476, 0, 0, 478, 479, 2491, + 0, 473, 474, 0, 476, 0, 0, 478, 479, 2492, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, - 2492, 0, 489, 490, 491, 492, 0, 493, 494, 495, - 496, 497, 0, 0, 500, 0, 501, 2493, 503, 504, + 2493, 0, 489, 490, 491, 492, 0, 493, 494, 495, + 496, 497, 0, 0, 500, 0, 501, 2494, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 0, 0, 0, 0, 994, 0, 0, 0, 0, 0, 0, 528, 529, 530, 531, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 122, 123, 124, 125, 126, 127, 128, 129, 3212, 130, + 122, 123, 124, 125, 126, 127, 128, 129, 3177, 130, 131, 132, 3, 4, 0, 575, 0, 0, 0, 0, 580, 134, 135, 0, 582, 137, 138, 583, 140, 141, 142, 584, 585, 586, 587, 588, 0, 590, 148, 149, @@ -8170,7 +8175,7 @@ static const yytype_int16 yytable[] = 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 3556, 0, 0, 0, 122, 123, 124, 125, + 0, 0, 3572, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, @@ -8475,7 +8480,7 @@ static const yytype_int16 yytable[] = 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2159, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2161, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, @@ -8526,7 +8531,7 @@ static const yytype_int16 yytable[] = 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2306, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2308, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, @@ -8577,7 +8582,7 @@ static const yytype_int16 yytable[] = 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2599, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2600, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, @@ -8628,7 +8633,7 @@ static const yytype_int16 yytable[] = 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2742, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2745, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, @@ -8679,7 +8684,7 @@ static const yytype_int16 yytable[] = 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2969, 0, 0, 0, 122, + 0, 0, 0, 0, 0, 2976, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, @@ -8730,7 +8735,7 @@ static const yytype_int16 yytable[] = 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3455, 0, 0, 0, 122, 123, + 0, 0, 0, 0, 3419, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, @@ -8780,8 +8785,8 @@ static const yytype_int16 yytable[] = 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, 0, - 0, 0, 0, 0, 0, 0, 3791, 0, 0, 0, - 0, 0, 0, 2266, 0, 0, 0, 122, 123, 124, + 0, 0, 0, 0, 0, 0, 3817, 0, 0, 0, + 0, 0, 0, 2268, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, @@ -8832,7 +8837,7 @@ static const yytype_int16 yytable[] = 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2266, 0, 0, 0, 122, 123, 124, 125, + 0, 0, 2268, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, @@ -8881,60 +8886,60 @@ static const yytype_int16 yytable[] = 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, - 527, 528, 529, 530, 531, 3101, 1395, 836, 0, 0, - 2133, 1080, 0, 0, 0, 0, 0, 2134, 2135, 0, - 0, 3306, 2136, 2137, 2138, 122, 123, 124, 125, 126, + 527, 528, 529, 530, 531, 3483, 1395, 836, 0, 0, + 2135, 1080, 0, 0, 0, 0, 0, 2136, 2137, 0, + 0, 3273, 2138, 2139, 2140, 122, 123, 124, 125, 126, 127, 128, 129, 571, 130, 131, 132, 572, 573, 574, - 3102, 576, 577, 578, 579, 3103, 134, 135, 581, 3104, - 137, 138, 3105, 140, 141, 142, 0, 1539, 3106, 1541, - 1542, 589, 3107, 148, 149, 150, 151, 152, 591, 592, + 3484, 576, 577, 578, 579, 3485, 134, 135, 581, 3486, + 137, 138, 3487, 140, 141, 142, 0, 1539, 3488, 1541, + 1542, 589, 3489, 148, 149, 150, 151, 152, 591, 592, 153, 154, 155, 156, 1544, 1545, 159, 595, 160, 161, - 162, 163, 0, 597, 3108, 599, 3109, 167, 168, 169, - 170, 171, 3110, 173, 174, 175, 602, 176, 177, 178, - 179, 180, 181, 603, 3111, 183, 184, 185, 186, 187, + 162, 163, 0, 597, 3490, 599, 3491, 167, 168, 169, + 170, 171, 3492, 173, 174, 175, 602, 176, 177, 178, + 179, 180, 181, 603, 3493, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 1550, 194, 195, 1551, 197, 608, 198, 609, 199, 200, 201, 202, 203, 204, 610, 611, 205, 206, 207, 208, 612, 613, 209, 210, 1093, 212, 213, 614, 214, 215, 216, 615, 217, 218, 219, 220, 616, 221, 222, 223, 224, 0, 226, 227, 228, 229, 230, 231, 0, 619, 233, 620, 234, 235, 1552, - 237, 622, 238, 623, 239, 3112, 625, 3113, 242, 243, - 2472, 3114, 246, 247, 248, 629, 0, 0, 251, 252, - 632, 253, 254, 255, 256, 257, 258, 259, 3115, 261, + 237, 622, 238, 623, 239, 3494, 625, 3495, 242, 243, + 2473, 3496, 246, 247, 248, 629, 0, 0, 251, 252, + 632, 253, 254, 255, 256, 257, 258, 259, 3497, 261, 262, 263, 264, 634, 265, 266, 267, 268, 269, 270, - 271, 635, 272, 3116, 0, 275, 276, 277, 278, 279, - 1558, 1559, 640, 1560, 642, 283, 3117, 3118, 286, 3119, + 271, 635, 272, 3498, 0, 275, 276, 277, 278, 279, + 1558, 1559, 640, 1560, 642, 283, 3499, 3500, 286, 3501, 288, 289, 290, 646, 291, 292, 293, 647, 648, 294, - 3120, 296, 3121, 651, 298, 299, 300, 301, 302, 303, - 304, 305, 3122, 307, 308, 309, 310, 311, 312, 313, + 3502, 296, 3503, 651, 298, 299, 300, 301, 302, 303, + 304, 305, 3504, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, - 324, 325, 326, 327, 328, 1567, 3123, 1569, 332, 333, - 334, 3124, 657, 336, 337, 3125, 339, 659, 0, 341, - 1571, 343, 344, 345, 662, 346, 347, 663, 664, 3126, - 349, 350, 665, 666, 351, 352, 0, 3127, 355, 3128, + 324, 325, 326, 327, 328, 1567, 3505, 1569, 332, 333, + 334, 3506, 657, 336, 337, 3507, 339, 659, 0, 341, + 1571, 343, 344, 345, 662, 346, 347, 663, 664, 3508, + 349, 350, 665, 666, 351, 352, 0, 3509, 355, 3510, 0, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 671, 672, 673, 674, 370, 371, 0, - 3129, 374, 375, 0, 377, 378, 379, 678, 380, 381, + 3511, 374, 375, 0, 377, 378, 379, 678, 380, 381, 382, 383, 384, 385, 679, 386, 387, 388, 389, 390, 1575, 392, 393, 394, 395, 681, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 682, - 409, 410, 3130, 412, 413, 414, 1577, 416, 417, 418, + 409, 410, 3512, 412, 413, 414, 1577, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, - 685, 3131, 429, 430, 431, 432, 433, 434, 3132, 436, - 437, 688, 3133, 439, 440, 1581, 442, 691, 443, 444, + 685, 3513, 429, 430, 431, 432, 433, 434, 3514, 436, + 437, 688, 3515, 439, 440, 1581, 442, 691, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 3134, 458, 0, 694, 695, 460, 461, 696, - 462, 3135, 464, 465, 466, 467, 468, 469, 698, 470, + 455, 456, 3516, 458, 0, 694, 695, 460, 461, 696, + 462, 3517, 464, 465, 466, 467, 468, 469, 698, 470, 1584, 1585, 701, 702, 473, 474, 0, 476, 0, 705, - 478, 479, 3136, 481, 482, 483, 484, 485, 3137, 708, - 486, 487, 488, 3138, 710, 489, 490, 491, 492, 711, + 478, 479, 3518, 481, 482, 483, 484, 485, 3519, 708, + 486, 487, 488, 3520, 710, 489, 490, 491, 492, 711, 493, 494, 495, 496, 497, 0, 1589, 500, 714, 501, - 3139, 503, 504, 505, 506, 507, 508, 509, 716, 717, + 3521, 503, 504, 505, 506, 507, 508, 509, 716, 717, 510, 718, 719, 511, 512, 513, 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 528, 529, 530, 531, 0, 539, 0, 2139, 2140, 2141, - 2133, 3140, 3141, 2144, 2145, 2146, 2147, 2134, 2135, 0, - 0, 0, 2136, 2137, 2138, 122, 123, 124, 125, 126, + 528, 529, 530, 531, 0, 539, 0, 2141, 2142, 2143, + 2135, 3522, 3523, 2146, 2147, 2148, 2149, 2136, 2137, 0, + 0, 0, 2138, 2139, 2140, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, @@ -8983,8 +8988,8 @@ static const yytype_int16 yytable[] = 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, - 528, 529, 530, 531, 0, 0, 0, 2139, 2140, 2141, - 0, 2142, 2143, 2144, 2145, 2146, 2147, 1676, 0, 0, + 528, 529, 530, 531, 0, 0, 0, 2141, 2142, 2143, + 0, 2144, 2145, 2146, 2147, 2148, 2149, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, 1680, 1681, 1685, 1682, 1683, 1684, @@ -9020,11 +9025,11 @@ static const yytype_int16 yytable[] = 1694, 0, 1696, 0, 0, 1697, 0, 0, 0, 0, 0, 0, 0, 1691, 0, 1695, 0, 0, 1692, 1698, 1696, 0, 1699, 1697, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1698, 0, 0, + 0, 0, 1418, 1419, 0, 0, 0, 1698, 0, 0, 1699, 1693, 1694, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1696, 0, 1695, 1697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700, - 0, 0, 1698, 0, 0, 1699, 0, 0, 0, 0, + 0, 0, 1698, 1420, 1421, 1699, 0, 1422, 1423, 0, 0, 0, 0, 0, 0, 0, 0, 1700, 0, 0, 0, 0, 0, 0, 0, 1676, 0, 1696, 1677, 0, 1697, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, @@ -9032,175 +9037,103 @@ static const yytype_int16 yytable[] = 0, 0, 1700, 0, 1685, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1687, 0, 0, 0, 0, 0, 1700, 1688, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1424, 1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1689, 0, 0, 0, 0, 0, 0, 1700, 0, 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, - 1707, 1708, 1709, 1710, 0, 0, 0, 0, 3478, 1701, + 1707, 1708, 1709, 1710, 0, 0, 0, 0, 3626, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, - 1709, 1710, 0, 0, 0, 0, 3506, 1700, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, 1704, + 1709, 1710, 0, 0, 0, 0, 3690, 1700, 0, 0, + 0, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 0, + 0, 1434, 1435, 0, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 0, - 0, 3610, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, - 1706, 1707, 1708, 1709, 1710, 0, 1690, 0, 0, 3670, + 0, 3714, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, + 1706, 1707, 1708, 1709, 1710, 0, 1690, 1876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1691, 0, 0, 0, 1701, 1692, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, - 0, 0, 0, 0, 3692, 0, 1676, 0, 0, 1677, - 0, 1693, 1694, 1678, 1679, 1680, 1681, 0, 1682, 1683, - 1684, 0, 0, 0, 0, 0, 0, 1695, 0, 1701, - 0, 0, 1702, 1703, 1704, 1685, 1705, 1706, 1707, 1708, - 1709, 1710, 0, 0, 2994, 1687, 0, 0, 0, 0, - 0, 0, 1688, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3001, 0, 0, 0, 1436, 1437, 0, 0, + 0, 1693, 1694, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1695, 0, 1701, + 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, + 1709, 1710, 0, 0, 3433, 0, 0, 1438, 1439, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1696, 0, 0, - 1697, 0, 0, 0, 0, 0, 0, 0, 0, 1689, + 1697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1440, 1441, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1690, 0, 0, + 0, 1442, 1443, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700, 0, 0, - 0, 0, 0, 0, 1691, 0, 0, 0, 0, 1692, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1693, 1694, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1695, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1696, 0, - 0, 1697, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1698, 0, 0, 1699, 1701, - 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, - 1709, 1710, 0, 0, 3468, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1700, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 570, 0, 0, 0, - 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, - 1708, 1709, 1710, 0, 0, 3650, 122, 123, 124, 125, - 126, 127, 128, 129, 571, 130, 131, 132, 572, 573, - 574, 575, 576, 577, 578, 579, 580, 134, 135, 581, - 582, 137, 138, 583, 140, 141, 142, 584, 585, 586, - 587, 588, 589, 590, 148, 149, 150, 151, 152, 591, - 592, 153, 154, 155, 156, 593, 594, 159, 595, 160, - 161, 162, 163, 596, 597, 598, 599, 600, 167, 168, - 169, 170, 171, 601, 173, 174, 175, 602, 176, 177, - 178, 179, 180, 181, 603, 604, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 606, 194, 195, 607, - 197, 608, 198, 609, 199, 200, 201, 202, 203, 204, - 610, 611, 205, 206, 207, 208, 612, 613, 209, 210, - 211, 212, 213, 614, 214, 215, 216, 615, 217, 218, - 219, 220, 616, 221, 222, 223, 224, 617, 226, 227, - 228, 229, 230, 231, 618, 619, 233, 620, 234, 235, - 621, 237, 622, 238, 623, 239, 624, 625, 626, 242, - 243, 627, 628, 246, 247, 248, 629, 630, 631, 251, - 252, 632, 253, 254, 255, 256, 257, 258, 259, 633, - 261, 262, 263, 264, 634, 265, 266, 267, 268, 269, - 270, 271, 635, 272, 636, 637, 275, 276, 277, 278, - 279, 638, 639, 640, 641, 642, 283, 643, 644, 286, - 645, 288, 289, 290, 646, 291, 292, 293, 647, 648, - 294, 649, 296, 650, 651, 298, 299, 300, 301, 302, - 303, 304, 305, 652, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, - 323, 324, 325, 326, 327, 328, 653, 654, 655, 332, - 333, 334, 656, 657, 336, 337, 658, 339, 659, 660, - 341, 661, 343, 344, 345, 662, 346, 347, 663, 664, - 348, 349, 350, 665, 666, 351, 352, 667, 668, 355, - 669, 670, 358, 359, 360, 361, 362, 363, 364, 365, - 366, 367, 368, 369, 671, 672, 673, 674, 370, 371, - 675, 676, 374, 375, 677, 377, 378, 379, 678, 380, - 381, 382, 383, 384, 385, 679, 386, 387, 388, 389, - 390, 680, 392, 393, 394, 395, 681, 396, 397, 398, - 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, - 682, 409, 410, 683, 412, 413, 414, 684, 416, 417, - 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, - 428, 685, 686, 429, 430, 431, 432, 433, 434, 687, - 436, 437, 688, 689, 439, 440, 690, 442, 691, 443, - 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, - 454, 455, 456, 692, 458, 693, 694, 695, 460, 461, - 696, 462, 697, 464, 465, 466, 467, 468, 469, 698, - 470, 699, 700, 701, 702, 473, 474, 703, 476, 704, - 705, 478, 479, 706, 481, 482, 483, 484, 485, 707, - 708, 486, 487, 488, 709, 710, 489, 490, 491, 492, - 711, 493, 494, 495, 496, 497, 712, 713, 500, 714, - 501, 715, 503, 504, 505, 506, 507, 508, 509, 716, - 717, 510, 718, 719, 511, 512, 513, 514, 515, 516, - 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, - 730, 528, 529, 530, 531, 539, 0, 0, 0, 0, - 0, 0, 0, 0, 2172, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, - 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, - 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, - 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, - 153, 154, 155, 156, 157, 158, 159, 0, 160, 161, - 162, 163, 164, 0, 0, 0, 166, 167, 168, 169, - 170, 171, 0, 173, 174, 175, 0, 176, 177, 178, - 179, 180, 181, 0, 0, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, - 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 0, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, - 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, - 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, - 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, - 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, - 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, - 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, - 288, 289, 290, 0, 291, 292, 293, 0, 0, 294, - 0, 296, 0, 0, 298, 299, 300, 301, 302, 303, - 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, + 0, 0, 0, 0, 0, 570, 0, 0, 0, 1701, + 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, + 1709, 1710, 0, 0, 3670, 122, 123, 124, 125, 126, + 127, 128, 129, 571, 130, 131, 132, 572, 573, 574, + 575, 576, 577, 578, 579, 580, 134, 135, 581, 582, + 137, 138, 583, 140, 141, 142, 584, 585, 586, 587, + 588, 589, 590, 148, 149, 150, 151, 152, 591, 592, + 153, 154, 155, 156, 593, 594, 159, 595, 160, 161, + 162, 163, 596, 597, 598, 599, 600, 167, 168, 169, + 170, 171, 601, 173, 174, 175, 602, 176, 177, 178, + 179, 180, 181, 603, 604, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 606, 194, 195, 607, 197, + 608, 198, 609, 199, 200, 201, 202, 203, 204, 610, + 611, 205, 206, 207, 208, 612, 613, 209, 210, 211, + 212, 213, 614, 214, 215, 216, 615, 217, 218, 219, + 220, 616, 221, 222, 223, 224, 617, 226, 227, 228, + 229, 230, 231, 618, 619, 233, 620, 234, 235, 621, + 237, 622, 238, 623, 239, 624, 625, 626, 242, 243, + 627, 628, 246, 247, 248, 629, 630, 631, 251, 252, + 632, 253, 254, 255, 256, 257, 258, 259, 633, 261, + 262, 263, 264, 634, 265, 266, 267, 268, 269, 270, + 271, 635, 272, 636, 637, 275, 276, 277, 278, 279, + 638, 639, 640, 641, 642, 283, 643, 644, 286, 645, + 288, 289, 290, 646, 291, 292, 293, 647, 648, 294, + 649, 296, 650, 651, 298, 299, 300, 301, 302, 303, + 304, 305, 652, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, - 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, - 334, 335, 0, 336, 337, 0, 339, 0, 340, 341, - 342, 343, 344, 345, 0, 346, 347, 0, 0, 348, - 349, 350, 0, 0, 351, 352, 353, 0, 355, 0, - 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, - 367, 368, 369, 0, 0, 0, 0, 370, 371, 372, - 0, 374, 375, 376, 377, 378, 379, 0, 380, 381, - 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, - 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, - 409, 410, 0, 412, 413, 414, 415, 416, 417, 418, + 324, 325, 326, 327, 328, 653, 654, 655, 332, 333, + 334, 656, 657, 336, 337, 658, 339, 659, 660, 341, + 661, 343, 344, 345, 662, 346, 347, 663, 664, 348, + 349, 350, 665, 666, 351, 352, 667, 668, 355, 669, + 670, 358, 359, 360, 361, 362, 363, 364, 365, 366, + 367, 368, 369, 671, 672, 673, 674, 370, 371, 675, + 676, 374, 375, 677, 377, 378, 379, 678, 380, 381, + 382, 383, 384, 385, 679, 386, 387, 388, 389, 390, + 680, 392, 393, 394, 395, 681, 396, 397, 398, 399, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 682, + 409, 410, 683, 412, 413, 414, 684, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, - 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, - 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, + 685, 686, 429, 430, 431, 432, 433, 434, 687, 436, + 437, 688, 689, 439, 440, 690, 442, 691, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, - 462, 0, 464, 465, 466, 467, 468, 469, 0, 470, - 471, 472, 0, 0, 473, 474, 475, 476, 477, 0, - 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, - 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, - 493, 494, 495, 496, 497, 498, 499, 500, 0, 501, - 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, - 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, + 455, 456, 692, 458, 693, 694, 695, 460, 461, 696, + 462, 697, 464, 465, 466, 467, 468, 469, 698, 470, + 699, 700, 701, 702, 473, 474, 703, 476, 704, 705, + 478, 479, 706, 481, 482, 483, 484, 485, 707, 708, + 486, 487, 488, 709, 710, 489, 490, 491, 492, 711, + 493, 494, 495, 496, 497, 712, 713, 500, 714, 501, + 715, 503, 504, 505, 506, 507, 508, 509, 716, 717, + 510, 718, 719, 511, 512, 513, 514, 515, 516, 720, + 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, - 0, 0, 0, 2886, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, @@ -9250,242 +9183,304 @@ static const yytype_int16 yytable[] = 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, - 529, 530, 531, 994, 1395, 836, 0, 0, 0, 1080, - 0, 0, 2889, 0, 0, 0, 0, 0, 0, 0, + 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, + 0, 0, 2891, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, - 129, 0, 130, 131, 132, 0, 0, 0, 575, 0, - 0, 0, 0, 580, 134, 135, 0, 582, 137, 138, - 583, 140, 141, 142, 584, 585, 586, 587, 588, 0, - 590, 148, 149, 150, 151, 152, 0, 0, 153, 154, - 155, 156, 593, 594, 159, 0, 160, 161, 162, 163, - 596, 0, 598, 0, 600, 167, 168, 169, 170, 171, - 601, 173, 174, 175, 0, 176, 177, 178, 179, 180, - 181, 0, 604, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 606, 194, 195, 607, 197, 0, 198, + 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, + 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, + 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, + 155, 156, 157, 158, 159, 0, 160, 161, 162, 163, + 164, 0, 0, 0, 166, 167, 168, 169, 170, 171, + 0, 173, 174, 175, 0, 176, 177, 178, 179, 180, + 181, 0, 0, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 0, - 221, 222, 223, 224, 617, 226, 227, 228, 229, 230, - 231, 618, 1396, 233, 0, 234, 235, 621, 237, 0, - 238, 0, 239, 624, 0, 626, 242, 243, 627, 628, - 246, 247, 248, 0, 630, 631, 251, 252, 0, 253, - 254, 255, 256, 257, 258, 259, 633, 261, 262, 263, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, + 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, + 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, + 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, - 272, 636, 637, 275, 276, 277, 278, 279, 638, 639, - 0, 641, 0, 283, 643, 644, 286, 645, 288, 289, - 290, 0, 291, 292, 293, 0, 0, 294, 649, 296, - 650, 0, 298, 299, 300, 301, 302, 303, 304, 305, - 652, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, + 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, + 290, 0, 291, 292, 293, 0, 0, 294, 0, 296, + 0, 0, 298, 299, 300, 301, 302, 303, 304, 305, + 541, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, 653, 654, 655, 332, 333, 334, 656, - 0, 336, 337, 658, 339, 0, 660, 341, 661, 343, - 344, 345, 0, 346, 347, 1397, 0, 348, 349, 350, - 0, 0, 351, 352, 667, 668, 355, 669, 670, 358, + 326, 327, 328, 329, 0, 331, 332, 333, 334, 335, + 0, 336, 337, 0, 339, 0, 340, 341, 342, 343, + 344, 345, 0, 346, 347, 0, 0, 348, 349, 350, + 0, 0, 351, 352, 353, 0, 355, 0, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, - 369, 0, 0, 0, 0, 370, 371, 675, 676, 374, - 375, 677, 377, 378, 379, 0, 380, 381, 382, 383, - 384, 385, 0, 386, 387, 388, 389, 390, 680, 392, + 369, 0, 0, 0, 0, 370, 371, 372, 0, 374, + 375, 376, 377, 378, 379, 0, 380, 381, 382, 383, + 384, 385, 0, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, - 683, 412, 413, 414, 684, 416, 417, 418, 419, 420, - 421, 422, 423, 424, 425, 426, 427, 428, 0, 686, - 429, 430, 431, 432, 433, 434, 687, 436, 437, 0, - 689, 439, 440, 690, 442, 0, 443, 444, 445, 446, + 0, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, + 429, 430, 431, 432, 433, 434, 435, 436, 437, 0, + 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, - 692, 458, 693, 0, 0, 460, 461, 0, 462, 697, - 464, 465, 466, 467, 468, 469, 0, 470, 699, 700, - 0, 0, 473, 474, 703, 476, 704, 1398, 478, 479, - 706, 481, 482, 483, 484, 485, 0, 0, 486, 487, - 488, 709, 0, 489, 490, 491, 492, 0, 493, 494, - 495, 496, 497, 712, 713, 500, 0, 501, 715, 503, + 542, 458, 459, 0, 0, 460, 461, 0, 462, 0, + 464, 465, 466, 467, 468, 469, 0, 470, 471, 472, + 0, 0, 473, 474, 475, 476, 477, 0, 478, 479, + 480, 481, 482, 483, 484, 485, 0, 0, 486, 487, + 488, 0, 0, 489, 490, 491, 492, 0, 493, 494, + 495, 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, - 0, 511, 512, 513, 514, 515, 516, 720, 721, 722, - 723, 724, 725, 726, 727, 728, 729, 730, 528, 529, - 530, 531, 0, 0, 1676, 0, 0, 1677, 0, 1399, - 1400, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, - 0, 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, - 1679, 1680, 1681, 1685, 1682, 1683, 1684, 0, 2272, 0, + 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, + 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, + 530, 531, 994, 1395, 836, 0, 0, 0, 1080, 0, + 0, 2894, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, + 0, 130, 131, 132, 0, 0, 0, 575, 0, 0, + 0, 0, 580, 134, 135, 0, 582, 137, 138, 583, + 140, 141, 142, 584, 585, 586, 587, 588, 0, 590, + 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, + 156, 593, 594, 159, 0, 160, 161, 162, 163, 596, + 0, 598, 0, 600, 167, 168, 169, 170, 171, 601, + 173, 174, 175, 0, 176, 177, 178, 179, 180, 181, + 0, 604, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 606, 194, 195, 607, 197, 0, 198, 0, + 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, + 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, + 222, 223, 224, 617, 226, 227, 228, 229, 230, 231, + 618, 1396, 233, 0, 234, 235, 621, 237, 0, 238, + 0, 239, 624, 0, 626, 242, 243, 627, 628, 246, + 247, 248, 0, 630, 631, 251, 252, 0, 253, 254, + 255, 256, 257, 258, 259, 633, 261, 262, 263, 264, + 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, + 636, 637, 275, 276, 277, 278, 279, 638, 639, 0, + 641, 0, 283, 643, 644, 286, 645, 288, 289, 290, + 0, 291, 292, 293, 0, 0, 294, 649, 296, 650, + 0, 298, 299, 300, 301, 302, 303, 304, 305, 652, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, + 327, 328, 653, 654, 655, 332, 333, 334, 656, 0, + 336, 337, 658, 339, 0, 660, 341, 661, 343, 344, + 345, 0, 346, 347, 1397, 0, 348, 349, 350, 0, + 0, 351, 352, 667, 668, 355, 669, 670, 358, 359, + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, + 0, 0, 0, 0, 370, 371, 675, 676, 374, 375, + 677, 377, 378, 379, 0, 380, 381, 382, 383, 384, + 385, 0, 386, 387, 388, 389, 390, 680, 392, 393, + 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 0, 409, 410, 683, + 412, 413, 414, 684, 416, 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, 427, 428, 0, 686, 429, + 430, 431, 432, 433, 434, 687, 436, 437, 0, 689, + 439, 440, 690, 442, 0, 443, 444, 445, 446, 447, + 448, 449, 450, 451, 452, 453, 454, 455, 456, 692, + 458, 693, 0, 0, 460, 461, 0, 462, 697, 464, + 465, 466, 467, 468, 469, 0, 470, 699, 700, 0, + 0, 473, 474, 703, 476, 704, 1398, 478, 479, 706, + 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, + 709, 0, 489, 490, 491, 492, 0, 493, 494, 495, + 496, 497, 712, 713, 500, 0, 501, 715, 503, 504, + 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, + 511, 512, 513, 514, 515, 516, 720, 721, 722, 723, + 724, 725, 726, 727, 728, 729, 730, 528, 529, 530, + 531, 0, 0, 1676, 0, 0, 1677, 0, 1399, 1400, + 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, 0, + 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, + 1680, 1681, 1685, 1682, 1683, 1684, 0, 2274, 0, 0, + 0, 0, 1687, 0, 0, 0, 0, 0, 0, 1688, + 1685, 0, 0, 0, 0, 0, 1676, 0, 0, 1677, + 1687, 0, 0, 1678, 1679, 1680, 1681, 1688, 1682, 1683, + 1684, 0, 0, 0, 1676, 0, 1689, 1677, 0, 0, + 0, 1678, 1679, 1680, 1681, 1685, 1682, 1683, 1684, 1979, + 0, 0, 0, 0, 1689, 1687, 0, 0, 0, 0, + 0, 0, 1688, 1685, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1687, 0, 0, 0, 0, 0, 0, - 1688, 1685, 0, 0, 0, 0, 0, 1676, 0, 0, - 1677, 1687, 0, 0, 1678, 1679, 1680, 1681, 1688, 1682, - 1683, 1684, 0, 0, 0, 1676, 0, 1689, 1677, 0, - 0, 0, 1678, 1679, 1680, 1681, 1685, 1682, 1683, 1684, - 0, 0, 0, 0, 0, 1689, 1687, 0, 0, 0, - 0, 0, 0, 1688, 1685, 0, 0, 0, 1979, 0, - 0, 0, 0, 0, 1687, 0, 0, 0, 0, 0, - 0, 1688, 0, 2273, 0, 0, 0, 0, 0, 0, - 1689, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1689, 0, - 0, 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, - 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 0, - 0, 0, 0, 0, 0, 1690, 0, 0, 0, 0, - 0, 1685, 0, 2015, 0, 0, 0, 0, 2016, 0, - 0, 1687, 1691, 1690, 0, 0, 0, 1692, 1688, 0, + 1688, 0, 2275, 0, 0, 0, 0, 0, 0, 1689, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1691, 0, 0, 0, 0, 1692, 0, 3779, 0, 0, - 1693, 1694, 0, 0, 0, 1689, 0, 0, 1690, 0, - 0, 0, 0, 0, 0, 0, 1695, 0, 1693, 1694, - 0, 0, 0, 0, 0, 1691, 1690, 0, 0, 0, - 1692, 0, 0, 0, 1695, 0, 0, 0, 0, 0, - 0, 0, 0, 1691, 0, 0, 0, 0, 1692, 0, - 0, 0, 0, 1693, 1694, 0, 1696, 0, 0, 1697, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1695, - 0, 1693, 1694, 1698, 1696, 0, 1699, 1697, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1695, 0, 0, - 0, 1698, 0, 0, 1699, 0, 0, 0, 0, 0, - 0, 0, 0, 1690, 0, 0, 0, 0, 0, 1696, - 0, 0, 1697, 0, 0, 0, 0, 0, 0, 0, - 1691, 0, 0, 0, 0, 1692, 1698, 1696, 0, 1699, - 1697, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1698, 0, 0, 1699, 1693, 1694, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3780, - 0, 0, 0, 0, 1695, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1700, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1676, - 0, 0, 1677, 0, 1700, 0, 1678, 1679, 1680, 1681, - 0, 1682, 1683, 1684, 1696, 0, 0, 1697, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1685, 0, - 0, 1698, 2021, 0, 1699, 0, 0, 0, 1687, 1700, - 0, 0, 0, 0, 0, 1688, 0, 0, 0, 0, - 0, 0, 0, 2276, 0, 0, 0, 1700, 1986, 0, + 0, 0, 0, 0, 0, 0, 0, 1689, 0, 0, + 0, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, + 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 0, 0, + 0, 0, 0, 0, 1690, 0, 0, 0, 0, 0, + 1685, 3805, 0, 0, 2021, 0, 0, 0, 0, 0, + 1687, 1691, 1690, 0, 0, 0, 1692, 1688, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1691, + 0, 0, 0, 0, 1692, 0, 0, 0, 0, 1693, + 1694, 0, 0, 0, 1689, 0, 0, 1690, 0, 0, + 0, 0, 0, 0, 0, 1695, 0, 1693, 1694, 0, + 0, 0, 0, 0, 1691, 1690, 0, 0, 0, 1692, + 0, 0, 0, 1695, 0, 0, 0, 0, 0, 0, + 0, 0, 1691, 0, 0, 0, 0, 1692, 0, 0, + 0, 0, 1693, 1694, 0, 1696, 0, 0, 1697, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1695, 0, + 1693, 1694, 1698, 1696, 0, 1699, 1697, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1695, 0, 0, 0, + 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, + 0, 0, 1690, 0, 0, 0, 0, 0, 1696, 0, + 0, 1697, 0, 0, 0, 0, 0, 0, 0, 1691, + 0, 0, 0, 3806, 1692, 1698, 1696, 0, 1699, 1697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1689, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1698, 0, 0, 1699, 1693, 1694, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1701, 0, + 0, 0, 0, 1695, 0, 0, 0, 0, 0, 0, + 1986, 0, 0, 0, 0, 1700, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1676, 0, + 0, 1677, 0, 1700, 0, 1678, 1679, 1680, 1681, 0, + 1682, 1683, 1684, 1696, 0, 0, 1697, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1685, 0, 0, + 1698, 0, 0, 1699, 0, 0, 0, 1687, 1700, 0, + 0, 0, 0, 0, 1688, 0, 0, 0, 0, 0, + 0, 0, 2278, 0, 0, 0, 1700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1689, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1701, 0, 0, + 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, + 0, 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, + 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, + 0, 0, 0, 1700, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, + 1708, 1709, 1710, 0, 2026, 0, 0, 0, 1701, 1690, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, - 1710, 0, 0, 0, 0, 0, 1701, 0, 0, 1702, - 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, - 0, 0, 0, 0, 1700, 0, 1676, 0, 0, 1677, - 0, 0, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, - 1684, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, - 1707, 1708, 1709, 1710, 0, 1685, 0, 0, 0, 1701, - 1690, 0, 1702, 1703, 1704, 1687, 1705, 1706, 1707, 1708, - 1709, 1710, 1688, 0, 0, 0, 0, 1691, 1676, 0, - 0, 1677, 1692, 0, 0, 1678, 1679, 1680, 1681, 0, - 1682, 1683, 1684, 0, 0, 0, 0, 0, 0, 1689, - 0, 0, 0, 0, 0, 1693, 1694, 1685, 0, 0, - 0, 2028, 0, 0, 0, 0, 0, 1687, 0, 0, - 0, 1695, 0, 0, 1688, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1701, 0, 0, 1702, - 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, - 0, 1689, 0, 0, 0, 0, 0, 0, 0, 1676, - 0, 1696, 1677, 0, 1697, 0, 1678, 1679, 1680, 1681, - 0, 1682, 1683, 1684, 0, 0, 0, 0, 1698, 0, - 0, 1699, 0, 0, 0, 0, 0, 0, 1685, 0, - 0, 0, 2026, 0, 0, 0, 0, 1690, 1687, 0, - 0, 0, 0, 0, 0, 1688, 0, 0, 0, 0, - 0, 0, 0, 0, 1691, 0, 0, 0, 0, 1692, + 1710, 0, 0, 0, 0, 0, 1691, 1676, 0, 0, + 1677, 1692, 0, 0, 1678, 1679, 1680, 1681, 0, 1682, + 1683, 1684, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1693, 1694, 1685, 0, 0, 0, + 2028, 0, 0, 0, 0, 0, 1687, 0, 0, 0, + 1695, 0, 0, 1688, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, + 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, + 1689, 0, 0, 0, 0, 0, 0, 0, 1676, 0, + 1696, 1677, 0, 1697, 0, 1678, 1679, 1680, 1681, 0, + 1682, 1683, 1684, 0, 0, 0, 0, 1698, 0, 0, + 1699, 0, 0, 0, 0, 0, 0, 1685, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1687, 0, 0, + 0, 0, 0, 0, 1688, 1676, 0, 0, 1677, 0, + 0, 0, 1678, 1679, 1680, 1681, 2640, 1682, 1683, 1684, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1689, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1693, 1694, 0, 0, 0, 0, 0, 1690, - 0, 0, 0, 0, 0, 0, 0, 0, 1695, 0, - 0, 0, 0, 0, 0, 0, 1691, 0, 0, 0, - 0, 1692, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1700, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1693, 1694, 0, 0, 1696, 0, - 0, 1697, 0, 0, 0, 0, 0, 0, 0, 0, - 1695, 0, 0, 0, 0, 1698, 0, 0, 1699, 0, - 2164, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1690, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1691, 0, 0, - 1696, 0, 1692, 1697, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1698, 0, 0, - 1699, 0, 0, 0, 0, 1693, 1694, 0, 0, 0, + 0, 1689, 0, 0, 1685, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1687, 0, 0, 0, 1690, 0, + 0, 1688, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1691, 0, 0, 0, 0, + 1692, 0, 0, 0, 0, 0, 0, 0, 1689, 0, + 1700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1693, 1694, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1695, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2166, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1695, 0, 1701, 0, 0, 1702, 1703, 1704, 0, - 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, 0, 0, - 0, 0, 0, 1676, 0, 0, 1677, 0, 1700, 0, - 1678, 1679, 1680, 1681, 2637, 1682, 1683, 1684, 0, 0, - 0, 1696, 0, 0, 1697, 0, 0, 0, 0, 0, - 0, 0, 1685, 0, 0, 0, 0, 0, 1698, 0, - 0, 1699, 1687, 0, 0, 0, 0, 0, 0, 1688, + 0, 0, 0, 0, 0, 0, 1691, 0, 0, 1696, + 0, 1692, 1697, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1698, 0, 0, 1699, + 0, 0, 0, 0, 1693, 1694, 1690, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1695, 0, 1701, 1691, 0, 1702, 1703, 1704, 1692, 1705, + 1706, 1707, 1708, 1709, 1710, 0, 1676, 0, 0, 1677, + 0, 0, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, + 1684, 1693, 1694, 0, 0, 0, 0, 0, 0, 0, + 1696, 0, 0, 1697, 0, 1685, 0, 1695, 0, 0, + 0, 0, 0, 0, 0, 1687, 0, 1698, 0, 0, + 1699, 0, 1688, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700, + 0, 0, 0, 0, 0, 1676, 0, 1696, 1677, 1689, + 1697, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, + 0, 0, 0, 0, 1698, 0, 0, 1699, 0, 0, + 0, 0, 0, 0, 1685, 0, 0, 0, 2975, 0, + 0, 0, 0, 0, 1687, 0, 0, 0, 0, 0, + 0, 1688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1689, 0, 1700, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1689, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1690, 0, 0, + 0, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, + 1707, 1708, 1709, 1710, 1691, 0, 0, 1700, 0, 1692, + 0, 0, 0, 1676, 0, 0, 1677, 0, 0, 0, + 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, 0, + 0, 0, 1693, 1694, 0, 0, 0, 0, 0, 0, + 0, 0, 1685, 0, 0, 0, 0, 0, 1695, 0, + 0, 0, 1687, 0, 0, 0, 1690, 0, 0, 1688, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1701, 1691, 0, 1702, 1703, 1704, 1692, 1705, + 1706, 1707, 1708, 1709, 1710, 0, 1689, 0, 1696, 0, + 0, 1697, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1693, 1694, 0, 0, 1698, 0, 0, 1699, 0, + 0, 0, 0, 0, 0, 0, 0, 1695, 0, 1701, + 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, + 1709, 1710, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1676, 0, 0, 1677, 0, 0, 1696, 1678, 1679, + 1697, 0, 0, 1682, 1683, 1684, 0, 0, 0, 0, + 0, 0, 0, 0, 1698, 0, 0, 1699, 0, 0, + 1685, 0, 0, 0, 1690, 0, 1676, 0, 0, 1677, + 1687, 0, 0, 1678, 1679, 1680, 1681, 1688, 1682, 1683, + 1684, 1691, 0, 0, 0, 0, 1692, 0, 1700, 0, + 0, 0, 0, 0, 0, 1685, 0, 0, 0, 0, + 0, 0, 0, 0, 1689, 1687, 0, 0, 0, 1693, + 1694, 0, 1688, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2959, 1695, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1689, 1676, 0, 0, 1677, 0, 0, 0, 1678, 1679, 1680, - 1681, 0, 1682, 1683, 1684, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1685, + 1681, 0, 1682, 1683, 1684, 0, 0, 1700, 0, 0, + 0, 0, 0, 0, 0, 1696, 0, 0, 1697, 1685, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1687, - 1701, 0, 0, 1702, 1703, 1704, 1688, 1705, 1706, 1707, - 1708, 1709, 1710, 0, 0, 0, 0, 0, 0, 0, - 0, 1700, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1689, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1701, 0, 1690, 1702, 1703, 1704, 0, 1705, - 1706, 1707, 1708, 1709, 1710, 0, 0, 0, 0, 0, - 0, 1691, 0, 0, 1676, 0, 1692, 1677, 0, 0, - 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1693, - 1694, 0, 0, 1685, 0, 0, 0, 2968, 0, 0, - 0, 0, 0, 1687, 0, 1695, 0, 0, 0, 0, - 1688, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1690, 0, 1701, 0, 0, 1702, 1703, 1704, 0, - 1705, 1706, 1707, 1708, 1709, 1710, 0, 1689, 1691, 0, - 0, 0, 0, 1692, 1676, 1696, 0, 1677, 1697, 0, - 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, - 0, 0, 1698, 0, 0, 1699, 1693, 1694, 0, 0, - 0, 0, 0, 1685, 0, 0, 0, 0, 0, 0, - 0, 0, 1695, 1687, 0, 0, 0, 0, 0, 0, - 1688, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1698, 0, 0, 1699, 1688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1689, 0, 0, - 0, 0, 1696, 0, 0, 1697, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1690, 0, 0, 0, 1698, + 1701, 0, 1690, 1702, 1703, 1704, 0, 1705, 1706, 1707, + 1708, 1709, 1710, 1689, 0, 0, 0, 0, 0, 1691, + 0, 0, 0, 0, 1692, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1690, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1693, 1694, 0, + 0, 0, 0, 0, 1691, 0, 0, 0, 0, 1692, + 0, 0, 0, 1695, 0, 0, 0, 0, 0, 1701, + 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, + 1709, 1710, 1889, 1694, 0, 1700, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1695, 0, + 0, 0, 0, 1696, 0, 0, 1697, 0, 0, 0, + 0, 1690, 0, 0, 0, 0, 0, 0, 0, 0, + 1698, 0, 0, 1699, 0, 0, 0, 0, 1691, 0, + 0, 0, 0, 1692, 0, 0, 0, 1676, 1696, 0, + 1677, 1697, 0, 0, 1678, 1679, 0, 0, 0, 1682, + 1683, 1684, 0, 0, 0, 1698, 1693, 1694, 1699, 0, + 0, 0, 0, 0, 0, 0, 1685, 0, 0, 0, + 0, 0, 1695, 0, 0, 0, 1687, 0, 0, 0, + 0, 0, 0, 1688, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1701, 0, 0, + 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, + 1689, 0, 1696, 0, 0, 1697, 0, 0, 0, 0, + 0, 0, 0, 1700, 0, 0, 0, 0, 0, 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1691, 0, 0, 0, 0, 1692, 0, 0, - 0, 0, 0, 0, 0, 1700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1693, 1694, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1695, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1691, 0, 0, 0, 1696, 1692, 0, 1697, - 0, 0, 1700, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1698, 0, 0, 1699, 0, 0, 0, - 1693, 1694, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1695, 1701, 2952, 0, - 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, - 0, 0, 0, 0, 0, 1676, 0, 0, 1677, 0, - 0, 0, 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, - 0, 0, 0, 0, 0, 0, 1696, 0, 0, 1697, - 0, 0, 0, 0, 1685, 0, 0, 0, 0, 0, - 0, 0, 0, 1698, 1687, 0, 1699, 0, 0, 0, - 0, 1688, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1701, 0, 1700, 1702, 1703, 1704, - 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 1689, 0, - 0, 0, 0, 1676, 0, 0, 1677, 0, 0, 0, - 1678, 1679, 1680, 1681, 0, 1682, 1683, 1684, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1685, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1687, 0, 0, 0, 0, 0, 0, 1688, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1700, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1689, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1690, 0, 1701, 0, - 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, - 1710, 0, 0, 1691, 0, 0, 0, 0, 1692, 0, + 0, 0, 0, 0, 0, 1691, 0, 0, 0, 0, + 1692, 0, 1700, 0, 0, 1701, 0, 0, 1702, 1703, + 1704, 0, 1705, 1706, 1707, 1708, 1709, 1710, 0, 0, + 0, 0, 0, 1693, 1694, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1695, + 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, + 1708, 1709, 1710, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1696, + 0, 0, 1697, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1698, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1889, 1694, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1695, 0, 0, + 0, 0, 0, 0, 1701, 0, 0, 1702, 1703, 1704, + 0, 1705, 1706, 1707, 1708, 2295, 1710, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1690, 0, 0, 0, 1701, 0, - 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 1709, - 1710, 1691, 0, 0, 0, 0, 1692, 1696, 0, 0, - 1697, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1698, 0, 0, 1699, 0, 1693, - 1694, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1695, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1696, 0, 0, 1697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1698, 0, 0, 1699, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1700, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -9493,19 +9488,215 @@ static const yytype_int16 yytable[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1701, - 0, 0, 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, - 1709, 1710, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 570, 0, 2190, 0, 0, 0, + 0, 1701, 0, 0, 1702, 1703, 1704, 0, 1705, 1706, + 1707, 1708, 1709, 1710, 122, 123, 124, 125, 126, 127, + 128, 129, 571, 130, 131, 132, 572, 573, 574, 575, + 576, 577, 578, 579, 580, 134, 135, 581, 582, 137, + 138, 583, 140, 141, 142, 584, 585, 586, 587, 588, + 589, 590, 148, 149, 150, 151, 152, 591, 592, 153, + 154, 155, 156, 593, 594, 159, 595, 160, 161, 162, + 163, 596, 597, 598, 599, 600, 167, 168, 169, 170, + 171, 601, 173, 174, 175, 602, 176, 177, 178, 179, + 180, 181, 603, 604, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 606, 194, 195, 607, 197, 608, + 198, 609, 199, 200, 201, 202, 203, 204, 610, 611, + 205, 206, 207, 208, 612, 613, 209, 210, 211, 212, + 213, 614, 214, 215, 216, 615, 217, 218, 219, 220, + 616, 221, 222, 223, 224, 617, 226, 227, 228, 229, + 230, 231, 618, 619, 233, 620, 234, 235, 621, 237, + 622, 238, 623, 239, 624, 625, 626, 242, 243, 627, + 628, 246, 247, 248, 629, 630, 631, 251, 252, 632, + 253, 254, 255, 256, 257, 258, 259, 633, 261, 262, + 263, 264, 634, 265, 266, 267, 268, 269, 270, 271, + 635, 272, 636, 637, 275, 276, 277, 278, 279, 638, + 639, 640, 641, 642, 283, 643, 644, 286, 645, 288, + 289, 290, 646, 291, 292, 293, 647, 648, 294, 649, + 296, 650, 651, 298, 299, 300, 301, 302, 303, 304, + 305, 652, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 653, 654, 655, 332, 333, 334, + 656, 657, 336, 337, 658, 339, 659, 660, 341, 661, + 343, 344, 345, 662, 346, 347, 663, 664, 348, 349, + 350, 665, 666, 351, 352, 667, 668, 355, 669, 670, + 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, + 368, 369, 671, 672, 673, 674, 370, 371, 675, 676, + 374, 375, 677, 377, 378, 379, 678, 380, 381, 382, + 383, 384, 385, 679, 386, 387, 388, 389, 390, 680, + 392, 393, 394, 395, 681, 396, 397, 398, 399, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 682, 409, + 410, 683, 412, 413, 414, 684, 416, 417, 418, 419, + 420, 421, 422, 423, 424, 425, 426, 427, 428, 685, + 686, 429, 430, 431, 432, 433, 434, 687, 436, 437, + 688, 689, 439, 440, 690, 442, 691, 443, 444, 445, + 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, + 456, 692, 458, 693, 694, 695, 460, 461, 696, 462, + 697, 464, 465, 466, 467, 468, 469, 698, 470, 699, + 700, 701, 702, 473, 474, 703, 476, 704, 705, 478, + 479, 706, 481, 482, 483, 484, 485, 707, 708, 486, + 487, 488, 709, 710, 489, 490, 491, 492, 711, 493, + 494, 495, 496, 497, 712, 713, 500, 714, 501, 715, + 503, 504, 505, 506, 507, 508, 509, 716, 717, 510, + 718, 719, 511, 512, 513, 514, 515, 516, 720, 721, + 722, 723, 724, 725, 726, 727, 728, 729, 730, 528, + 529, 530, 531, 570, 0, 836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, + 129, 571, 130, 131, 132, 572, 573, 574, 575, 576, + 577, 578, 579, 580, 134, 135, 581, 582, 137, 138, + 583, 140, 141, 142, 584, 585, 586, 587, 588, 589, + 590, 148, 149, 150, 151, 152, 591, 592, 153, 154, + 155, 156, 593, 594, 159, 595, 160, 161, 162, 163, + 596, 597, 598, 599, 600, 167, 168, 169, 170, 171, + 601, 173, 174, 175, 602, 176, 177, 178, 179, 180, + 181, 603, 604, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 606, 194, 195, 607, 197, 608, 198, + 609, 199, 200, 201, 202, 203, 204, 610, 611, 205, + 206, 207, 208, 612, 613, 209, 210, 211, 212, 213, + 614, 214, 215, 216, 615, 217, 218, 219, 220, 616, + 221, 222, 223, 224, 617, 226, 227, 228, 229, 230, + 231, 618, 619, 233, 620, 234, 235, 621, 237, 622, + 238, 623, 239, 624, 625, 626, 242, 243, 627, 628, + 246, 247, 248, 629, 630, 631, 251, 252, 632, 253, + 254, 255, 256, 257, 258, 259, 633, 261, 262, 263, + 264, 634, 265, 266, 267, 268, 269, 270, 271, 635, + 272, 636, 637, 275, 276, 277, 278, 279, 638, 639, + 640, 641, 642, 283, 643, 644, 286, 645, 288, 289, + 290, 646, 291, 292, 293, 647, 648, 294, 649, 296, + 650, 651, 298, 299, 300, 301, 302, 303, 304, 305, + 652, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, 653, 654, 655, 332, 333, 334, 656, + 657, 336, 337, 658, 339, 659, 660, 341, 661, 343, + 344, 345, 662, 346, 347, 663, 664, 348, 349, 350, + 665, 666, 351, 352, 667, 668, 355, 669, 670, 358, + 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + 369, 671, 672, 673, 674, 370, 371, 675, 676, 374, + 375, 677, 377, 378, 379, 678, 380, 381, 382, 383, + 384, 385, 679, 386, 387, 388, 389, 390, 680, 392, + 393, 394, 395, 681, 396, 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 682, 409, 410, + 683, 412, 413, 414, 684, 416, 417, 418, 419, 420, + 421, 422, 423, 424, 425, 426, 427, 428, 685, 686, + 429, 430, 431, 432, 433, 434, 687, 436, 437, 688, + 689, 439, 440, 690, 442, 691, 443, 444, 445, 446, + 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, + 692, 458, 693, 694, 695, 460, 461, 696, 462, 697, + 464, 465, 466, 467, 468, 469, 698, 470, 699, 700, + 701, 702, 473, 474, 703, 476, 704, 705, 478, 479, + 706, 481, 482, 483, 484, 485, 707, 708, 486, 487, + 488, 709, 710, 489, 490, 491, 492, 711, 493, 494, + 495, 496, 497, 712, 713, 500, 714, 501, 715, 503, + 504, 505, 506, 507, 508, 509, 716, 717, 510, 718, + 719, 511, 512, 513, 514, 515, 516, 720, 721, 722, + 723, 724, 725, 726, 727, 728, 729, 730, 528, 529, + 530, 531, 570, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, + 571, 130, 131, 132, 572, 573, 574, 575, 576, 577, + 578, 579, 580, 134, 135, 581, 582, 137, 138, 583, + 140, 141, 142, 584, 585, 586, 587, 588, 589, 590, + 148, 149, 150, 151, 152, 591, 592, 153, 154, 155, + 156, 593, 594, 159, 595, 160, 161, 162, 163, 596, + 597, 598, 599, 600, 167, 168, 169, 170, 171, 601, + 173, 174, 175, 602, 176, 177, 178, 179, 180, 181, + 603, 604, 183, 184, 185, 186, 187, 188, 605, 190, + 191, 192, 606, 194, 195, 607, 197, 608, 198, 609, + 199, 200, 201, 202, 203, 204, 610, 611, 205, 206, + 207, 208, 612, 613, 209, 210, 211, 212, 213, 614, + 214, 215, 216, 615, 217, 218, 219, 220, 616, 221, + 222, 223, 224, 617, 226, 227, 228, 229, 230, 231, + 618, 619, 233, 620, 234, 235, 621, 237, 622, 238, + 623, 239, 624, 625, 626, 242, 243, 627, 628, 246, + 247, 248, 629, 630, 631, 251, 252, 632, 253, 254, + 255, 256, 257, 258, 259, 633, 261, 262, 263, 264, + 634, 265, 266, 267, 268, 269, 270, 271, 635, 272, + 636, 637, 275, 276, 277, 278, 279, 638, 639, 640, + 641, 642, 283, 643, 644, 286, 645, 288, 289, 290, + 646, 291, 292, 293, 647, 648, 294, 649, 296, 650, + 651, 298, 299, 300, 301, 302, 303, 304, 305, 652, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, + 327, 328, 653, 654, 655, 332, 333, 334, 656, 657, + 336, 337, 658, 339, 659, 660, 341, 661, 343, 344, + 345, 662, 346, 347, 663, 664, 348, 349, 350, 665, + 666, 351, 352, 667, 668, 355, 669, 670, 358, 359, + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, + 671, 672, 673, 674, 370, 371, 675, 676, 374, 375, + 677, 377, 378, 379, 678, 380, 381, 382, 383, 384, + 385, 679, 386, 387, 388, 389, 390, 680, 392, 393, + 394, 395, 681, 396, 397, 398, 399, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 682, 409, 410, 683, + 412, 413, 414, 684, 416, 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, 427, 428, 685, 686, 429, + 430, 431, 432, 433, 434, 687, 436, 437, 688, 689, + 439, 440, 690, 442, 691, 443, 444, 445, 446, 447, + 448, 449, 450, 451, 452, 453, 454, 455, 456, 692, + 458, 693, 694, 695, 460, 461, 696, 462, 697, 464, + 465, 466, 467, 468, 469, 698, 470, 699, 700, 701, + 702, 473, 474, 703, 476, 704, 705, 478, 479, 706, + 481, 482, 483, 484, 485, 707, 708, 486, 487, 488, + 709, 710, 489, 490, 491, 492, 711, 493, 494, 495, + 496, 497, 712, 713, 500, 714, 501, 715, 503, 504, + 505, 506, 507, 508, 509, 716, 717, 510, 718, 719, + 511, 512, 513, 514, 515, 516, 720, 721, 722, 723, + 724, 725, 726, 727, 728, 729, 730, 528, 529, 530, + 531, 570, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 122, 123, 124, 125, 126, 127, 128, 129, 571, + 130, 131, 132, 572, 573, 574, 575, 576, 577, 578, + 579, 580, 134, 135, 581, 582, 137, 138, 583, 140, + 141, 142, 584, 585, 586, 587, 588, 589, 590, 148, + 149, 150, 151, 152, 591, 592, 153, 154, 155, 156, + 593, 594, 159, 595, 160, 161, 162, 163, 596, 597, + 598, 599, 600, 167, 168, 169, 170, 171, 601, 173, + 174, 175, 602, 176, 177, 178, 179, 180, 181, 603, + 604, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 606, 194, 195, 607, 197, 608, 198, 609, 199, + 200, 201, 202, 203, 204, 610, 611, 205, 206, 207, + 208, 612, 613, 209, 210, 211, 212, 213, 614, 214, + 215, 216, 615, 217, 218, 219, 220, 616, 221, 222, + 223, 224, 617, 226, 227, 228, 229, 230, 231, 618, + 619, 233, 620, 234, 235, 621, 237, 622, 238, 623, + 239, 624, 625, 626, 242, 243, 627, 628, 246, 247, + 248, 629, 630, 631, 251, 252, 632, 253, 254, 255, + 256, 257, 970, 259, 633, 261, 262, 263, 264, 634, + 265, 266, 267, 268, 269, 270, 271, 635, 272, 636, + 637, 275, 276, 277, 278, 279, 638, 639, 640, 641, + 642, 283, 643, 644, 286, 645, 288, 289, 290, 646, + 291, 292, 293, 647, 648, 294, 649, 296, 650, 651, + 298, 299, 300, 301, 302, 303, 304, 305, 652, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, 653, 654, 655, 332, 333, 334, 656, 657, 336, + 337, 658, 339, 659, 660, 341, 661, 343, 344, 345, + 662, 346, 347, 663, 664, 348, 349, 350, 665, 666, + 351, 352, 667, 668, 355, 669, 670, 358, 359, 360, + 361, 362, 363, 364, 365, 366, 367, 368, 369, 671, + 672, 673, 674, 370, 371, 675, 676, 374, 375, 677, + 377, 378, 379, 678, 380, 381, 382, 383, 384, 385, + 679, 386, 387, 388, 389, 390, 680, 392, 393, 394, + 395, 681, 396, 397, 398, 399, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 682, 409, 410, 683, 412, + 413, 414, 684, 416, 417, 418, 419, 420, 421, 422, + 423, 424, 425, 426, 427, 428, 685, 686, 429, 430, + 431, 432, 433, 434, 687, 436, 437, 688, 689, 439, + 440, 690, 442, 691, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 456, 692, 458, + 693, 694, 695, 460, 461, 696, 462, 697, 464, 465, + 466, 467, 468, 469, 698, 470, 699, 700, 701, 702, + 473, 474, 703, 476, 704, 705, 478, 479, 706, 481, + 482, 483, 484, 485, 707, 708, 486, 487, 488, 709, + 710, 489, 490, 491, 492, 711, 493, 494, 495, 496, + 497, 712, 713, 500, 714, 501, 715, 503, 504, 505, + 506, 507, 508, 509, 716, 717, 510, 718, 719, 511, + 512, 513, 514, 515, 516, 720, 721, 722, 723, 724, + 725, 726, 727, 728, 729, 730, 528, 529, 530, 531, + 570, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 570, 0, 2188, 0, 0, 0, 0, 1701, 0, 0, - 1702, 1703, 1704, 0, 1705, 1706, 1707, 1708, 2293, 1710, 122, 123, 124, 125, 126, 127, 128, 129, 571, 130, 131, 132, 572, 573, 574, 575, 576, 577, 578, 579, 580, 134, 135, 581, 582, 137, 138, 583, 140, 141, @@ -9557,7 +9748,7 @@ static const yytype_int16 yytable[] = 726, 727, 728, 729, 730, 528, 529, 530, 531, 570, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, - 123, 124, 125, 126, 127, 128, 129, 571, 130, 131, + 123, 124, 125, 2351, 127, 128, 129, 571, 130, 131, 132, 572, 573, 574, 575, 576, 577, 578, 579, 580, 134, 135, 581, 582, 137, 138, 583, 140, 141, 142, 584, 585, 586, 587, 588, 589, 590, 148, 149, 150, @@ -9565,10 +9756,10 @@ static const yytype_int16 yytable[] = 159, 595, 160, 161, 162, 163, 596, 597, 598, 599, 600, 167, 168, 169, 170, 171, 601, 173, 174, 175, 602, 176, 177, 178, 179, 180, 181, 603, 604, 183, - 184, 185, 186, 187, 188, 605, 190, 191, 192, 606, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 606, 194, 195, 607, 197, 608, 198, 609, 199, 200, 201, 202, 203, 204, 610, 611, 205, 206, 207, 208, 612, - 613, 209, 210, 211, 212, 213, 614, 214, 215, 216, + 613, 209, 210, 211, 2352, 213, 614, 214, 215, 216, 615, 217, 218, 219, 220, 616, 221, 222, 223, 224, 617, 226, 227, 228, 229, 230, 231, 618, 619, 233, 620, 234, 235, 621, 237, 622, 238, 623, 239, 624, @@ -9594,7 +9785,7 @@ static const yytype_int16 yytable[] = 406, 407, 408, 682, 409, 410, 683, 412, 413, 414, 684, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 685, 686, 429, 430, 431, 432, - 433, 434, 687, 436, 437, 688, 689, 439, 440, 690, + 433, 2353, 687, 436, 437, 688, 689, 439, 440, 690, 442, 691, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 692, 458, 693, 694, 695, 460, 461, 696, 462, 697, 464, 465, 466, 467, @@ -9605,467 +9796,467 @@ static const yytype_int16 yytable[] = 713, 500, 714, 501, 715, 503, 504, 505, 506, 507, 508, 509, 716, 717, 510, 718, 719, 511, 512, 513, 514, 515, 516, 720, 721, 722, 723, 724, 725, 726, - 727, 728, 729, 730, 528, 529, 530, 531, 570, 0, + 727, 728, 729, 730, 528, 529, 530, 531, 994, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, - 124, 125, 126, 127, 128, 129, 571, 130, 131, 132, - 572, 573, 574, 575, 576, 577, 578, 579, 580, 134, - 135, 581, 582, 137, 138, 583, 140, 141, 142, 584, - 585, 586, 587, 588, 589, 590, 148, 149, 150, 151, - 152, 591, 592, 153, 154, 155, 156, 593, 594, 159, - 595, 160, 161, 162, 163, 596, 597, 598, 599, 600, - 167, 168, 169, 170, 171, 601, 173, 174, 175, 602, - 176, 177, 178, 179, 180, 181, 603, 604, 183, 184, + 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, + 3, 4, 0, 575, 0, 0, 0, 0, 580, 134, + 135, 0, 582, 137, 138, 583, 140, 141, 142, 584, + 585, 586, 587, 588, 0, 590, 148, 149, 150, 151, + 152, 0, 0, 153, 154, 155, 156, 593, 594, 159, + 0, 160, 161, 162, 163, 596, 0, 598, 0, 600, + 167, 168, 169, 170, 171, 601, 173, 174, 175, 0, + 176, 177, 178, 179, 180, 181, 0, 604, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 606, 194, - 195, 607, 197, 608, 198, 609, 199, 200, 201, 202, - 203, 204, 610, 611, 205, 206, 207, 208, 612, 613, - 209, 210, 211, 212, 213, 614, 214, 215, 216, 615, - 217, 218, 219, 220, 616, 221, 222, 223, 224, 617, - 226, 227, 228, 229, 230, 231, 618, 619, 233, 620, - 234, 235, 621, 237, 622, 238, 623, 239, 624, 625, - 626, 242, 243, 627, 628, 246, 247, 248, 629, 630, - 631, 251, 252, 632, 253, 254, 255, 256, 257, 970, - 259, 633, 261, 262, 263, 264, 634, 265, 266, 267, - 268, 269, 270, 271, 635, 272, 636, 637, 275, 276, - 277, 278, 279, 638, 639, 640, 641, 642, 283, 643, - 644, 286, 645, 288, 289, 290, 646, 291, 292, 293, - 647, 648, 294, 649, 296, 650, 651, 298, 299, 300, + 195, 607, 197, 0, 198, 0, 199, 200, 201, 202, + 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, + 209, 210, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 0, 221, 222, 223, 224, 617, + 226, 227, 228, 229, 230, 231, 618, 0, 233, 0, + 234, 235, 621, 237, 0, 238, 0, 239, 624, 0, + 626, 242, 243, 627, 628, 246, 247, 248, 0, 630, + 631, 251, 252, 0, 253, 254, 255, 256, 257, 258, + 259, 633, 261, 262, 263, 264, 0, 265, 266, 267, + 268, 269, 270, 271, 0, 272, 636, 637, 275, 276, + 277, 278, 279, 638, 639, 0, 641, 0, 283, 643, + 644, 286, 645, 288, 289, 290, 0, 291, 292, 293, + 0, 0, 294, 649, 296, 650, 0, 298, 299, 300, 301, 302, 303, 304, 305, 652, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 653, 654, - 655, 332, 333, 334, 656, 657, 336, 337, 658, 339, - 659, 660, 341, 661, 343, 344, 345, 662, 346, 347, - 663, 664, 348, 349, 350, 665, 666, 351, 352, 667, + 655, 332, 333, 334, 656, 0, 336, 337, 658, 339, + 0, 660, 341, 661, 343, 344, 345, 0, 346, 347, + 0, 0, 348, 349, 350, 0, 0, 351, 352, 667, 668, 355, 669, 670, 358, 359, 360, 361, 362, 363, - 364, 365, 366, 367, 368, 369, 671, 672, 673, 674, + 364, 365, 366, 367, 368, 369, 0, 0, 0, 0, 370, 371, 675, 676, 374, 375, 677, 377, 378, 379, - 678, 380, 381, 382, 383, 384, 385, 679, 386, 387, - 388, 389, 390, 680, 392, 393, 394, 395, 681, 396, + 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, + 388, 389, 390, 680, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 682, 409, 410, 683, 412, 413, 414, 684, + 407, 408, 0, 409, 410, 683, 412, 413, 414, 684, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 685, 686, 429, 430, 431, 432, 433, - 434, 687, 436, 437, 688, 689, 439, 440, 690, 442, - 691, 443, 444, 445, 446, 447, 448, 449, 450, 451, - 452, 453, 454, 455, 456, 692, 458, 693, 694, 695, - 460, 461, 696, 462, 697, 464, 465, 466, 467, 468, - 469, 698, 470, 699, 700, 701, 702, 473, 474, 703, - 476, 704, 705, 478, 479, 706, 481, 482, 483, 484, - 485, 707, 708, 486, 487, 488, 709, 710, 489, 490, - 491, 492, 711, 493, 494, 495, 496, 497, 712, 713, - 500, 714, 501, 715, 503, 504, 505, 506, 507, 508, - 509, 716, 717, 510, 718, 719, 511, 512, 513, 514, + 426, 427, 428, 0, 686, 429, 430, 431, 432, 433, + 434, 687, 436, 437, 0, 689, 439, 440, 690, 442, + 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, + 452, 453, 454, 455, 456, 692, 458, 693, 0, 0, + 460, 461, 0, 462, 697, 464, 465, 466, 467, 468, + 469, 0, 470, 699, 700, 0, 0, 473, 474, 703, + 476, 704, 0, 478, 479, 706, 481, 482, 483, 484, + 485, 0, 0, 486, 487, 488, 709, 0, 489, 490, + 491, 492, 0, 493, 494, 495, 496, 497, 712, 713, + 500, 0, 501, 715, 503, 504, 505, 506, 507, 508, + 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 720, 721, 722, 723, 724, 725, 726, 727, - 728, 729, 730, 528, 529, 530, 531, 570, 0, 0, + 728, 729, 730, 528, 529, 530, 531, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, - 125, 126, 127, 128, 129, 571, 130, 131, 132, 572, - 573, 574, 575, 576, 577, 578, 579, 580, 134, 135, - 581, 582, 137, 138, 583, 140, 141, 142, 584, 585, - 586, 587, 588, 589, 590, 148, 149, 150, 151, 152, - 591, 592, 153, 154, 155, 156, 593, 594, 159, 595, - 160, 161, 162, 163, 596, 597, 598, 599, 600, 167, - 168, 169, 170, 171, 601, 173, 174, 175, 602, 176, - 177, 178, 179, 180, 181, 603, 604, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 606, 194, 195, - 607, 197, 608, 198, 609, 199, 200, 201, 202, 203, - 204, 610, 611, 205, 206, 207, 208, 612, 613, 209, - 210, 211, 212, 213, 614, 214, 215, 216, 615, 217, - 218, 219, 220, 616, 221, 222, 223, 224, 617, 226, - 227, 228, 229, 230, 231, 618, 619, 233, 620, 234, - 235, 621, 237, 622, 238, 623, 239, 624, 625, 626, - 242, 243, 627, 628, 246, 247, 248, 629, 630, 631, - 251, 252, 632, 253, 254, 255, 256, 257, 258, 259, - 633, 261, 262, 263, 264, 634, 265, 266, 267, 268, - 269, 270, 271, 635, 272, 636, 637, 275, 276, 277, - 278, 279, 638, 639, 640, 641, 642, 283, 643, 644, - 286, 645, 288, 289, 290, 646, 291, 292, 293, 647, - 648, 294, 649, 296, 650, 651, 298, 299, 300, 301, - 302, 303, 304, 305, 652, 307, 308, 309, 310, 311, + 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, + 0, 0, 0, 0, 0, 0, 0, 133, 134, 135, + 0, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 0, 0, 148, 149, 150, 151, 152, + 0, 805, 153, 154, 155, 156, 157, 158, 159, 0, + 160, 161, 162, 163, 806, 0, 807, 0, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 0, 176, + 177, 178, 179, 180, 181, 0, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 0, 198, 0, 199, 200, 201, 202, 203, + 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, + 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 0, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 808, 0, 233, 0, 234, + 235, 236, 237, 0, 238, 0, 239, 240, 0, 241, + 242, 243, 244, 245, 246, 247, 248, 0, 249, 250, + 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 0, 265, 266, 267, 268, + 269, 270, 271, 0, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 0, 282, 0, 283, 284, 285, + 286, 287, 288, 289, 290, 0, 291, 292, 293, 0, + 0, 294, 295, 296, 297, 0, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, 653, 654, 655, - 332, 333, 334, 656, 657, 336, 337, 658, 339, 659, - 660, 341, 661, 343, 344, 345, 662, 346, 347, 663, - 664, 348, 349, 350, 665, 666, 351, 352, 667, 668, - 355, 669, 670, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 671, 672, 673, 674, 370, - 371, 675, 676, 374, 375, 677, 377, 378, 379, 678, - 380, 381, 382, 383, 384, 385, 679, 386, 387, 388, - 389, 390, 680, 392, 393, 394, 395, 681, 396, 397, + 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, + 332, 333, 334, 335, 0, 336, 337, 338, 339, 0, + 810, 341, 342, 343, 344, 345, 0, 346, 347, 0, + 0, 348, 349, 350, 0, 0, 351, 352, 353, 354, + 355, 356, 812, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 0, 0, 0, 0, 370, + 371, 813, 373, 374, 375, 376, 377, 378, 379, 0, + 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, + 389, 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 682, 409, 410, 683, 412, 413, 414, 684, 416, + 408, 0, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, - 427, 428, 685, 686, 429, 430, 431, 432, 433, 434, - 687, 436, 437, 688, 689, 439, 440, 690, 442, 691, + 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 0, 438, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, - 453, 454, 455, 456, 692, 458, 693, 694, 695, 460, - 461, 696, 462, 697, 464, 465, 466, 467, 468, 469, - 698, 470, 699, 700, 701, 702, 473, 474, 703, 476, - 704, 705, 478, 479, 706, 481, 482, 483, 484, 485, - 707, 708, 486, 487, 488, 709, 710, 489, 490, 491, - 492, 711, 493, 494, 495, 496, 497, 712, 713, 500, - 714, 501, 715, 503, 504, 505, 506, 507, 508, 509, - 716, 717, 510, 718, 719, 511, 512, 513, 514, 515, - 516, 720, 721, 722, 723, 724, 725, 726, 727, 728, - 729, 730, 528, 529, 530, 531, 570, 0, 0, 0, + 453, 454, 455, 456, 457, 458, 815, 0, 0, 460, + 461, 0, 462, 463, 464, 465, 466, 467, 468, 469, + 0, 470, 471, 472, 0, 0, 473, 474, 816, 476, + 817, 0, 478, 479, 818, 481, 482, 483, 484, 485, + 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, + 492, 0, 493, 494, 495, 496, 497, 498, 499, 500, + 0, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, + 526, 527, 528, 529, 530, 531, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, - 2349, 127, 128, 129, 571, 130, 131, 132, 572, 573, - 574, 575, 576, 577, 578, 579, 580, 134, 135, 581, - 582, 137, 138, 583, 140, 141, 142, 584, 585, 586, - 587, 588, 589, 590, 148, 149, 150, 151, 152, 591, - 592, 153, 154, 155, 156, 593, 594, 159, 595, 160, - 161, 162, 163, 596, 597, 598, 599, 600, 167, 168, - 169, 170, 171, 601, 173, 174, 175, 602, 176, 177, - 178, 179, 180, 181, 603, 604, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 606, 194, 195, 607, - 197, 608, 198, 609, 199, 200, 201, 202, 203, 204, - 610, 611, 205, 206, 207, 208, 612, 613, 209, 210, - 211, 2350, 213, 614, 214, 215, 216, 615, 217, 218, - 219, 220, 616, 221, 222, 223, 224, 617, 226, 227, - 228, 229, 230, 231, 618, 619, 233, 620, 234, 235, - 621, 237, 622, 238, 623, 239, 624, 625, 626, 242, - 243, 627, 628, 246, 247, 248, 629, 630, 631, 251, - 252, 632, 253, 254, 255, 256, 257, 258, 259, 633, - 261, 262, 263, 264, 634, 265, 266, 267, 268, 269, - 270, 271, 635, 272, 636, 637, 275, 276, 277, 278, - 279, 638, 639, 640, 641, 642, 283, 643, 644, 286, - 645, 288, 289, 290, 646, 291, 292, 293, 647, 648, - 294, 649, 296, 650, 651, 298, 299, 300, 301, 302, - 303, 304, 305, 652, 307, 308, 309, 310, 311, 312, + 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, + 0, 0, 0, 0, 0, 0, 133, 134, 135, 0, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, + 0, 153, 154, 155, 156, 157, 158, 159, 0, 160, + 161, 162, 163, 164, 0, 165, 0, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 0, 176, 177, + 178, 179, 180, 181, 0, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, + 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 0, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, + 236, 237, 0, 238, 0, 239, 240, 0, 241, 242, + 243, 244, 245, 246, 247, 248, 0, 249, 250, 251, + 252, 0, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, + 270, 271, 0, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 0, 282, 0, 283, 284, 285, 286, + 287, 288, 289, 290, 0, 291, 292, 293, 0, 0, + 294, 295, 296, 297, 0, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, - 323, 324, 325, 326, 327, 328, 653, 654, 655, 332, - 333, 334, 656, 657, 336, 337, 658, 339, 659, 660, - 341, 661, 343, 344, 345, 662, 346, 347, 663, 664, - 348, 349, 350, 665, 666, 351, 352, 667, 668, 355, - 669, 670, 358, 359, 360, 361, 362, 363, 364, 365, - 366, 367, 368, 369, 671, 672, 673, 674, 370, 371, - 675, 676, 374, 375, 677, 377, 378, 379, 678, 380, - 381, 382, 383, 384, 385, 679, 386, 387, 388, 389, - 390, 680, 392, 393, 394, 395, 681, 396, 397, 398, + 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 0, 336, 337, 338, 339, 0, 340, + 341, 342, 343, 344, 345, 0, 346, 347, 0, 0, + 348, 349, 350, 0, 0, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, + 366, 367, 368, 369, 0, 0, 0, 0, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 0, 380, + 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, + 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, - 682, 409, 410, 683, 412, 413, 414, 684, 416, 417, + 0, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, - 428, 685, 686, 429, 430, 431, 432, 433, 2351, 687, - 436, 437, 688, 689, 439, 440, 690, 442, 691, 443, + 428, 0, 0, 429, 430, 431, 432, 433, 434, 435, + 436, 437, 0, 438, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, - 454, 455, 456, 692, 458, 693, 694, 695, 460, 461, - 696, 462, 697, 464, 465, 466, 467, 468, 469, 698, - 470, 699, 700, 701, 702, 473, 474, 703, 476, 704, - 705, 478, 479, 706, 481, 482, 483, 484, 485, 707, - 708, 486, 487, 488, 709, 710, 489, 490, 491, 492, - 711, 493, 494, 495, 496, 497, 712, 713, 500, 714, - 501, 715, 503, 504, 505, 506, 507, 508, 509, 716, - 717, 510, 718, 719, 511, 512, 513, 514, 515, 516, - 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, - 730, 528, 529, 530, 531, 994, 0, 0, 0, 0, + 454, 455, 456, 457, 458, 459, 0, 0, 460, 461, + 0, 462, 463, 464, 465, 466, 467, 468, 469, 0, + 470, 471, 472, 0, 0, 473, 474, 475, 476, 477, + 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, + 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, + 0, 493, 494, 495, 496, 497, 498, 499, 500, 0, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 0, + 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, + 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, - 127, 128, 129, 0, 130, 131, 132, 3, 4, 0, - 575, 0, 0, 0, 0, 580, 134, 135, 0, 582, - 137, 138, 583, 140, 141, 142, 584, 585, 586, 587, - 588, 0, 590, 148, 149, 150, 151, 152, 0, 0, - 153, 154, 155, 156, 593, 594, 159, 0, 160, 161, - 162, 163, 596, 0, 598, 0, 600, 167, 168, 169, - 170, 171, 601, 173, 174, 175, 0, 176, 177, 178, - 179, 180, 181, 0, 604, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 606, 194, 195, 607, 197, + 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, + 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, + 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, + 153, 154, 155, 156, 157, 158, 159, 1812, 160, 161, + 162, 163, 164, 0, 0, 1813, 166, 167, 168, 169, + 170, 171, 0, 173, 174, 175, 1814, 176, 177, 178, + 179, 180, 181, 0, 0, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 0, 221, 222, 223, 224, 617, 226, 227, 228, - 229, 230, 231, 618, 0, 233, 0, 234, 235, 621, - 237, 0, 238, 0, 239, 624, 0, 626, 242, 243, - 627, 628, 246, 247, 248, 0, 630, 631, 251, 252, - 0, 253, 254, 255, 256, 257, 258, 259, 633, 261, + 220, 0, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, + 237, 0, 238, 1815, 239, 0, 0, 0, 242, 243, + 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, + 0, 253, 254, 255, 256, 257, 1816, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, - 271, 0, 272, 636, 637, 275, 276, 277, 278, 279, - 638, 639, 0, 641, 0, 283, 643, 644, 286, 645, + 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, + 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, 293, 0, 0, 294, - 649, 296, 650, 0, 298, 299, 300, 301, 302, 303, - 304, 305, 652, 307, 308, 309, 310, 311, 312, 313, + 0, 296, 0, 0, 298, 299, 300, 301, 302, 303, + 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, - 324, 325, 326, 327, 328, 653, 654, 655, 332, 333, - 334, 656, 0, 336, 337, 658, 339, 0, 660, 341, - 661, 343, 344, 345, 0, 346, 347, 0, 0, 348, - 349, 350, 0, 0, 351, 352, 667, 668, 355, 669, - 670, 358, 359, 360, 361, 362, 363, 364, 365, 366, - 367, 368, 369, 0, 0, 0, 0, 370, 371, 675, - 676, 374, 375, 677, 377, 378, 379, 0, 380, 381, + 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, + 334, 335, 0, 336, 337, 0, 339, 0, 340, 341, + 342, 343, 344, 345, 0, 346, 347, 0, 0, 348, + 349, 350, 0, 0, 351, 352, 353, 0, 355, 0, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, + 367, 368, 369, 0, 0, 0, 0, 370, 371, 372, + 0, 374, 375, 376, 377, 378, 379, 1817, 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, - 680, 392, 393, 394, 395, 0, 396, 397, 398, 399, + 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, - 409, 410, 683, 412, 413, 414, 684, 416, 417, 418, + 409, 410, 0, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, - 0, 686, 429, 430, 431, 432, 433, 434, 687, 436, - 437, 0, 689, 439, 440, 690, 442, 0, 443, 444, + 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, + 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 692, 458, 693, 0, 0, 460, 461, 0, - 462, 697, 464, 465, 466, 467, 468, 469, 0, 470, - 699, 700, 0, 0, 473, 474, 703, 476, 704, 0, - 478, 479, 706, 481, 482, 483, 484, 485, 0, 0, - 486, 487, 488, 709, 0, 489, 490, 491, 492, 0, - 493, 494, 495, 496, 497, 712, 713, 500, 0, 501, - 715, 503, 504, 505, 506, 507, 508, 509, 0, 0, - 510, 0, 0, 511, 512, 513, 514, 515, 516, 720, - 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, - 528, 529, 530, 531, 121, 0, 0, 0, 0, 0, + 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, + 462, 0, 464, 465, 466, 467, 468, 469, 0, 470, + 471, 472, 0, 0, 473, 474, 475, 476, 477, 0, + 478, 479, 480, 481, 482, 483, 484, 485, 0, 1818, + 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, + 493, 494, 495, 496, 497, 498, 499, 500, 0, 501, + 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, + 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, + 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, - 0, 0, 0, 0, 133, 134, 135, 0, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 0, 0, 148, 149, 150, 151, 152, 0, 805, 153, - 154, 155, 156, 157, 158, 159, 0, 160, 161, 162, - 163, 806, 0, 807, 0, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 0, 176, 177, 178, 179, - 180, 181, 0, 182, 183, 184, 185, 186, 187, 188, + 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, + 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, + 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, + 154, 155, 156, 157, 158, 159, 1812, 160, 161, 162, + 163, 164, 0, 0, 0, 166, 167, 168, 169, 170, + 171, 0, 173, 174, 175, 1814, 176, 177, 178, 179, + 180, 181, 0, 0, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 808, 0, 233, 0, 234, 235, 236, 237, - 0, 238, 0, 239, 240, 0, 241, 242, 243, 244, - 245, 246, 247, 248, 0, 249, 250, 251, 252, 0, - 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, + 0, 238, 1815, 239, 0, 0, 0, 242, 243, 540, + 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, + 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, - 0, 272, 273, 274, 275, 276, 277, 278, 279, 280, - 281, 0, 282, 0, 283, 284, 285, 286, 287, 288, - 289, 290, 0, 291, 292, 293, 0, 0, 294, 295, - 296, 297, 0, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, + 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, + 289, 290, 0, 291, 292, 293, 0, 0, 294, 0, + 296, 2443, 0, 298, 299, 300, 301, 302, 303, 304, + 305, 541, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 0, 336, 337, 338, 339, 0, 810, 341, 342, + 325, 326, 327, 328, 329, 0, 331, 332, 333, 334, + 335, 0, 336, 337, 0, 339, 0, 340, 341, 342, 343, 344, 345, 0, 346, 347, 0, 0, 348, 349, - 350, 0, 0, 351, 352, 353, 354, 355, 356, 812, + 350, 0, 0, 351, 352, 353, 0, 355, 0, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, - 368, 369, 0, 0, 0, 0, 370, 371, 813, 373, - 374, 375, 376, 377, 378, 379, 0, 380, 381, 382, + 368, 369, 0, 0, 0, 0, 370, 371, 372, 0, + 374, 375, 376, 377, 378, 379, 1817, 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, + 410, 0, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, 437, - 0, 438, 439, 440, 441, 442, 0, 443, 444, 445, + 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, - 456, 457, 458, 815, 0, 0, 460, 461, 0, 462, - 463, 464, 465, 466, 467, 468, 469, 0, 470, 471, - 472, 0, 0, 473, 474, 816, 476, 817, 0, 478, - 479, 818, 481, 482, 483, 484, 485, 0, 0, 486, + 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, + 0, 464, 465, 466, 467, 468, 469, 0, 470, 471, + 472, 0, 0, 473, 474, 475, 476, 477, 0, 478, + 479, 480, 481, 482, 483, 484, 485, 0, 1818, 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, 493, - 494, 495, 496, 497, 498, 499, 500, 0, 501, 502, + 494, 495, 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, - 529, 530, 531, 121, 0, 0, 0, 0, 0, 0, + 529, 530, 531, 1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, - 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, - 0, 0, 0, 133, 134, 135, 0, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 0, - 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, - 155, 156, 157, 158, 159, 0, 160, 161, 162, 163, - 164, 0, 165, 0, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 0, 176, 177, 178, 179, 180, - 181, 0, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 0, 198, + 129, 0, 130, 131, 132, 0, 0, 0, 1535, 0, + 0, -870, 0, 1536, 134, 135, 0, 1537, 137, 138, + 1538, 140, 141, 142, 0, 1539, 1540, 1541, 1542, 0, + 1543, 148, 149, 150, 151, 152, 0, 0, 153, 154, + 155, 156, 1544, 1545, 159, 0, 160, 161, 162, 163, + 0, 0, 1546, 0, 1547, 167, 168, 169, 170, 171, + 1548, 173, 174, 175, 0, 176, 177, 178, 179, 180, + 181, 0, 1549, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 1550, 194, 195, 1551, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, - 206, 207, 208, 0, 0, 209, 210, 211, 212, 213, + 206, 207, 208, 0, 0, 209, 210, 1093, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 0, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, - 238, 0, 239, 240, 0, 241, 242, 243, 244, 245, - 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 221, 222, 223, 224, 0, 226, 227, 228, 229, 230, + 231, 0, 0, 233, 0, 234, 235, 1552, 237, 0, + 238, 0, 239, 1553, 0, 1554, 242, 243, -870, 1555, + 246, 247, 248, 0, 0, 0, 251, 252, 0, 253, + 254, 255, 256, 257, 258, 259, 1556, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 0, 282, 0, 283, 284, 285, 286, 287, 288, 289, - 290, 0, 291, 292, 293, 0, 0, 294, 295, 296, - 297, 0, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 272, 1557, 0, 275, 276, 277, 278, 279, 1558, 1559, + 0, 1560, 0, 283, 1561, 1562, 286, 1563, 288, 289, + 290, 0, 291, 292, 293, 0, 0, 294, 1564, 296, + 1565, 0, 298, 299, 300, 301, 302, 303, 304, 305, + 1566, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, - 0, 336, 337, 338, 339, 0, 340, 341, 342, 343, + 326, 327, 328, 1567, 1568, 1569, 332, 333, 334, 0, + 0, 336, 337, 1570, 339, 0, 0, 341, 1571, 343, 344, 345, 0, 346, 347, 0, 0, 348, 349, 350, - 0, 0, 351, 352, 353, 354, 355, 356, 357, 358, + 0, 0, 351, 352, 0, 1572, 355, 1573, 0, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, - 369, 0, 0, 0, 0, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 0, 380, 381, 382, 383, - 384, 385, 0, 386, 387, 388, 389, 390, 391, 392, + 369, 0, 0, 0, 0, 370, 371, 0, 1574, 374, + 375, 0, 377, 378, 379, 0, 380, 381, 382, 383, + 384, 385, 0, 386, 387, 388, 389, 390, 1575, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, - 429, 430, 431, 432, 433, 434, 435, 436, 437, 0, - 438, 439, 440, 441, 442, 0, 443, 444, 445, 446, + 1576, 412, 413, 414, 1577, 416, 417, 418, 419, 420, + 421, 422, 423, 424, 425, 426, 427, 428, 0, 1578, + 429, 430, 431, 432, 433, 434, 1579, 436, 437, 0, + 1580, 439, 440, 1581, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, - 457, 458, 459, 0, 0, 460, 461, 0, 462, 463, - 464, 465, 466, 467, 468, 469, 0, 470, 471, 472, - 0, 0, 473, 474, 475, 476, 477, 0, 478, 479, - 480, 481, 482, 483, 484, 485, 0, 0, 486, 487, - 488, 0, 0, 489, 490, 491, 492, 0, 493, 494, - 495, 496, 497, 498, 499, 500, 0, 501, 502, 503, + 1582, 458, 0, 0, 0, 460, 461, 0, 462, 1583, + 464, 465, 466, 467, 468, 469, 0, 470, 1584, 1585, + 0, 0, 473, 474, 0, 476, 0, 0, 478, 479, + 1586, 481, 482, 483, 484, 485, 1587, 0, 486, 487, + 488, 1588, 0, 489, 490, 491, 492, 0, 493, 494, + 495, 496, 497, 0, 1589, 500, 0, 501, 1590, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, - 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, - 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, + 0, 511, 512, 513, 514, 515, 516, 539, 0, 564, + 0, 0, 0, 0, 0, 0, 0, 0, 528, 529, + 530, 531, 0, 0, 0, 0, 0, 122, 123, 124, + 125, 126, 127, 128, 129, 0, 130, 131, 132, 3, + 4, 0, 0, 0, 0, 0, 0, 0, 134, 135, + 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, + 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, + 0, 0, 153, 154, 155, 156, 157, 158, 159, 0, + 160, 161, 162, 163, 164, 0, 0, 0, 166, 167, + 168, 169, 170, 171, 0, 173, 174, 175, 0, 176, + 177, 178, 179, 180, 181, 0, 0, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 0, 198, 0, 199, 200, 201, 202, 203, + 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, + 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 0, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, + 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, + 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, + 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, + 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, + 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, + 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, + 286, 0, 288, 289, 290, 0, 291, 292, 293, 0, + 0, 294, 0, 296, 0, 0, 298, 299, 300, 301, + 302, 303, 304, 305, 541, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, 327, 328, 329, 0, 331, + 332, 333, 334, 335, 0, 336, 337, 0, 339, 0, + 340, 341, 342, 343, 344, 345, 0, 346, 347, 0, + 0, 348, 349, 350, 0, 0, 351, 352, 353, 0, + 355, 0, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 0, 0, 0, 0, 370, + 371, 372, 0, 374, 375, 376, 377, 378, 379, 0, + 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, + 389, 390, 391, 392, 393, 394, 395, 0, 396, 397, + 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 0, 409, 410, 0, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, + 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 0, 0, 439, 440, 441, 442, 0, + 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, + 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, + 461, 0, 462, 0, 464, 465, 466, 467, 468, 469, + 0, 470, 471, 472, 0, 0, 473, 474, 475, 476, + 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, + 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, + 492, 0, 493, 494, 495, 496, 497, 498, 499, 500, + 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, + 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, + 526, 527, 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, - 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, - 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, - 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, - 156, 157, 158, 159, 1812, 160, 161, 162, 163, 164, - 0, 0, 1813, 166, 167, 168, 169, 170, 171, 0, - 173, 174, 175, 1814, 176, 177, 178, 179, 180, 181, - 0, 0, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 0, 198, 0, - 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, - 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, - 1815, 239, 0, 0, 0, 242, 243, 540, 0, 246, - 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, - 255, 256, 257, 1816, 259, 0, 261, 262, 263, 264, - 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, - 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, - 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, - 0, 291, 292, 293, 0, 0, 294, 0, 296, 0, - 0, 298, 299, 300, 301, 302, 303, 304, 305, 541, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 329, 0, 331, 332, 333, 334, 335, 0, - 336, 337, 0, 339, 0, 340, 341, 342, 343, 344, - 345, 0, 346, 347, 0, 0, 348, 349, 350, 0, - 0, 351, 352, 353, 0, 355, 0, 357, 358, 359, - 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, - 0, 0, 0, 0, 370, 371, 372, 0, 374, 375, - 376, 377, 378, 379, 1817, 380, 381, 382, 383, 384, - 385, 0, 386, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 0, 409, 410, 0, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, - 430, 431, 432, 433, 434, 435, 436, 437, 0, 0, - 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, - 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, - 458, 459, 0, 0, 460, 461, 0, 462, 0, 464, - 465, 466, 467, 468, 469, 0, 470, 471, 472, 0, - 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, - 481, 482, 483, 484, 485, 0, 1818, 486, 487, 488, - 0, 0, 489, 490, 491, 492, 0, 493, 494, 495, - 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, - 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, - 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, + 126, 127, 128, 129, 565, 130, 131, 132, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, + 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, + 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, + 0, 153, 154, 155, 156, 157, 158, 159, 0, 160, + 161, 162, 163, 164, 0, 0, 0, 166, 167, 168, + 169, 170, 171, 0, 173, 174, 175, 0, 176, 177, + 178, 179, 180, 181, 0, 0, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, + 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 0, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, + 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, + 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, + 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, + 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, + 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, + 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, + 0, 288, 289, 290, 0, 291, 292, 293, 0, 0, + 294, 0, 296, 0, 0, 298, 299, 300, 301, 302, + 303, 304, 305, 541, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 325, 326, 327, 328, 329, 0, 331, 332, + 333, 334, 335, 0, 336, 337, 0, 339, 0, 340, + 341, 342, 343, 344, 345, 0, 346, 347, 0, 0, + 348, 349, 350, 0, 0, 351, 352, 353, 0, 355, + 0, 357, 358, 359, 360, 361, 362, 363, 364, 365, + 366, 367, 368, 369, 0, 0, 0, 0, 370, 371, + 372, 0, 374, 375, 376, 566, 378, 379, 0, 380, + 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, + 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, + 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 0, 409, 410, 0, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, + 428, 0, 0, 429, 430, 431, 432, 433, 434, 435, + 436, 437, 0, 0, 439, 440, 441, 442, 0, 443, + 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, + 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, + 0, 462, 0, 464, 465, 466, 467, 468, 469, 0, + 470, 471, 472, 0, 0, 473, 474, 475, 476, 477, + 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, + 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, + 0, 493, 494, 495, 496, 497, 498, 499, 500, 0, + 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, + 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, + 527, 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, - 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, - 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, - 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, - 157, 158, 159, 1812, 160, 161, 162, 163, 164, 0, - 0, 0, 166, 167, 168, 169, 170, 171, 0, 173, - 174, 175, 1814, 176, 177, 178, 179, 180, 181, 0, - 0, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 0, 198, 0, 199, - 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, - 208, 0, 0, 209, 210, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 0, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, - 0, 233, 0, 234, 235, 236, 237, 0, 238, 1815, - 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, - 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, - 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, - 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, - 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, - 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, - 291, 292, 293, 0, 0, 294, 0, 296, 2440, 0, - 298, 299, 300, 301, 302, 303, 304, 305, 541, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, - 328, 329, 0, 331, 332, 333, 334, 335, 0, 336, - 337, 0, 339, 0, 340, 341, 342, 343, 344, 345, - 0, 346, 347, 0, 0, 348, 349, 350, 0, 0, - 351, 352, 353, 0, 355, 0, 357, 358, 359, 360, - 361, 362, 363, 364, 365, 366, 367, 368, 369, 0, - 0, 0, 0, 370, 371, 372, 0, 374, 375, 376, - 377, 378, 379, 1817, 380, 381, 382, 383, 384, 385, - 0, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 0, 409, 410, 0, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, - 423, 424, 425, 426, 427, 428, 0, 0, 429, 430, - 431, 432, 433, 434, 435, 436, 437, 0, 0, 439, - 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, - 449, 450, 451, 452, 453, 454, 455, 456, 542, 458, - 459, 0, 0, 460, 461, 0, 462, 0, 464, 465, - 466, 467, 468, 469, 0, 470, 471, 472, 0, 0, - 473, 474, 475, 476, 477, 0, 478, 479, 480, 481, - 482, 483, 484, 485, 0, 1818, 486, 487, 488, 0, - 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, - 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, - 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, - 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, - 1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, + 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, + 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, + 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, + 153, 154, 155, 156, 157, 158, 159, 0, 160, 161, + 162, 163, 164, 0, 0, 0, 166, 167, 168, 169, + 170, 171, 0, 173, 174, 175, 0, 176, 177, 178, + 179, 180, 181, 0, 0, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, + 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, + 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, + 220, 0, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, + 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, + 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, + 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, + 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, + 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, + 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, + 288, 289, 290, 0, 291, 292, 293, 0, 0, 294, + 0, 296, 0, 0, 298, 299, 300, 301, 302, 303, + 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, + 334, 335, 0, 336, 337, 0, 339, 0, 340, 341, + 342, 343, 344, 345, 0, 346, 347, 0, 811, 348, + 349, 350, 0, 0, 351, 352, 353, 0, 355, 0, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, + 367, 368, 369, 0, 0, 0, 0, 370, 371, 372, + 0, 374, 375, 376, 377, 378, 379, 0, 380, 381, + 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, + 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, + 409, 410, 0, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, + 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, + 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, + 462, 0, 464, 465, 466, 467, 468, 469, 0, 470, + 471, 472, 0, 0, 473, 474, 475, 476, 477, 0, + 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, + 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, + 493, 494, 495, 496, 497, 498, 499, 500, 0, 501, + 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, + 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, + 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, - 131, 132, 0, 0, 0, 1535, 0, 0, -864, 0, - 1536, 134, 135, 0, 1537, 137, 138, 1538, 140, 141, - 142, 0, 1539, 1540, 1541, 1542, 0, 1543, 148, 149, - 150, 151, 152, 0, 0, 153, 154, 155, 156, 1544, - 1545, 159, 0, 160, 161, 162, 163, 0, 0, 1546, - 0, 1547, 167, 168, 169, 170, 171, 1548, 173, 174, - 175, 0, 176, 177, 178, 179, 180, 181, 0, 1549, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 1550, 194, 195, 1551, 197, 0, 198, 0, 199, 200, - 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, - 0, 0, 209, 210, 1093, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 0, 221, 222, 223, - 224, 0, 226, 227, 228, 229, 230, 231, 0, 0, - 233, 0, 234, 235, 1552, 237, 0, 238, 0, 239, - 1553, 0, 1554, 242, 243, -864, 1555, 246, 247, 248, - 0, 0, 0, 251, 252, 0, 253, 254, 255, 256, - 257, 258, 259, 1556, 261, 262, 263, 264, 0, 265, - 266, 267, 268, 269, 270, 271, 0, 272, 1557, 0, - 275, 276, 277, 278, 279, 1558, 1559, 0, 1560, 0, - 283, 1561, 1562, 286, 1563, 288, 289, 290, 0, 291, - 292, 293, 0, 0, 294, 1564, 296, 1565, 0, 298, - 299, 300, 301, 302, 303, 304, 305, 1566, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, - 1567, 1568, 1569, 332, 333, 334, 0, 0, 336, 337, - 1570, 339, 0, 0, 341, 1571, 343, 344, 345, 0, - 346, 347, 0, 0, 348, 349, 350, 0, 0, 351, - 352, 0, 1572, 355, 1573, 0, 358, 359, 360, 361, - 362, 363, 364, 365, 366, 367, 368, 369, 0, 0, - 0, 0, 370, 371, 0, 1574, 374, 375, 0, 377, - 378, 379, 0, 380, 381, 382, 383, 384, 385, 0, - 386, 387, 388, 389, 390, 1575, 392, 393, 394, 395, - 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 0, 409, 410, 1576, 412, 413, - 414, 1577, 416, 417, 418, 419, 420, 421, 422, 423, - 424, 425, 426, 427, 428, 0, 1578, 429, 430, 431, - 432, 433, 434, 1579, 436, 437, 0, 1580, 439, 440, - 1581, 442, 0, 443, 444, 445, 446, 447, 448, 449, - 450, 451, 452, 453, 454, 455, 456, 1582, 458, 0, - 0, 0, 460, 461, 0, 462, 1583, 464, 465, 466, - 467, 468, 469, 0, 470, 1584, 1585, 0, 0, 473, - 474, 0, 476, 0, 0, 478, 479, 1586, 481, 482, - 483, 484, 485, 1587, 0, 486, 487, 488, 1588, 0, - 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, - 0, 1589, 500, 0, 501, 1590, 503, 504, 505, 506, - 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, - 513, 514, 515, 516, 539, 0, 564, 0, 0, 0, - 0, 0, 0, 0, 0, 528, 529, 530, 531, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, - 128, 129, 0, 130, 131, 132, 3, 4, 0, 0, + 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, @@ -10081,7 +10272,7 @@ static const yytype_int16 yytable[] = 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, - 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, + 253, 254, 255, 256, 257, 923, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, @@ -10091,7 +10282,7 @@ static const yytype_int16 yytable[] = 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, 334, 335, 0, 336, 337, 0, 339, 0, 340, 341, 342, - 343, 344, 345, 0, 346, 347, 0, 0, 348, 349, + 343, 344, 345, 0, 346, 347, 0, 811, 348, 349, 350, 0, 0, 351, 352, 353, 0, 355, 0, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 0, 0, 0, 0, 370, 371, 372, 0, @@ -10116,7 +10307,7 @@ static const yytype_int16 yytable[] = 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, - 129, 565, 130, 131, 132, 0, 0, 0, 0, 0, + 129, 968, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, @@ -10146,7 +10337,7 @@ static const yytype_int16 yytable[] = 0, 0, 351, 352, 353, 0, 355, 0, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 0, 0, 0, 0, 370, 371, 372, 0, 374, - 375, 376, 566, 378, 379, 0, 380, 381, 382, 383, + 375, 376, 377, 378, 379, 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, @@ -10179,7 +10370,7 @@ static const yytype_int16 yytable[] = 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + 222, 223, 224, 225, 226, 227, 228, 229, 1207, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, @@ -10215,307 +10406,54 @@ static const yytype_int16 yytable[] = 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, - 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, + 531, 1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, - 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, - 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, + 130, 131, 132, 0, 0, 0, 1535, 0, 0, 0, + 0, 1536, 134, 135, 0, 1537, 137, 138, 1538, 140, + 141, 142, 0, 1539, 1540, 1541, 1542, 0, 1543, 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, - 157, 158, 159, 0, 160, 161, 162, 163, 164, 0, - 0, 0, 166, 167, 168, 169, 170, 171, 0, 173, + 1544, 1545, 159, 0, 160, 161, 162, 163, 0, 0, + 1546, 0, 1547, 167, 168, 169, 170, 171, 1548, 173, 174, 175, 0, 176, 177, 178, 179, 180, 181, 0, - 0, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 0, 198, 0, 199, + 1549, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 1550, 194, 195, 1551, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, - 208, 0, 0, 209, 210, 211, 212, 213, 0, 214, + 208, 0, 0, 209, 210, 1093, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, - 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, - 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, - 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, - 256, 257, 923, 259, 0, 261, 262, 263, 264, 0, - 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, - 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, - 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, - 291, 292, 293, 0, 0, 294, 0, 296, 0, 0, - 298, 299, 300, 301, 302, 303, 304, 305, 541, 307, + 223, 224, 0, 226, 227, 228, 229, 230, 231, 0, + 0, 233, 0, 234, 235, 1552, 237, 0, 238, 0, + 239, 1553, 0, 1554, 242, 243, 0, 1555, 246, 247, + 248, 0, 0, 0, 251, 252, 0, 253, 254, 255, + 256, 257, 258, 259, 1556, 261, 262, 263, 264, 0, + 265, 266, 267, 268, 269, 270, 271, 0, 272, 1557, + 0, 275, 276, 277, 278, 279, 1558, 1559, 0, 1560, + 0, 283, 1561, 1562, 286, 1563, 288, 289, 290, 0, + 291, 292, 293, 0, 0, 294, 1564, 296, 1565, 0, + 298, 299, 300, 301, 302, 303, 304, 305, 1566, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, - 328, 329, 0, 331, 332, 333, 334, 335, 0, 336, - 337, 0, 339, 0, 340, 341, 342, 343, 344, 345, - 0, 346, 347, 0, 811, 348, 349, 350, 0, 0, - 351, 352, 353, 0, 355, 0, 357, 358, 359, 360, + 328, 1567, 1568, 1569, 332, 333, 334, 0, 0, 336, + 337, 1570, 339, 0, 0, 341, 1571, 343, 344, 345, + 0, 346, 347, 0, 0, 348, 349, 350, 0, 0, + 351, 352, 0, 1572, 355, 1573, 0, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 0, - 0, 0, 0, 370, 371, 372, 0, 374, 375, 376, + 0, 0, 0, 370, 371, 0, 1574, 374, 375, 0, 377, 378, 379, 0, 380, 381, 382, 383, 384, 385, - 0, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 0, 386, 387, 388, 389, 390, 1575, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 0, 409, 410, 0, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, - 423, 424, 425, 426, 427, 428, 0, 0, 429, 430, - 431, 432, 433, 434, 435, 436, 437, 0, 0, 439, - 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, - 449, 450, 451, 452, 453, 454, 455, 456, 542, 458, - 459, 0, 0, 460, 461, 0, 462, 0, 464, 465, - 466, 467, 468, 469, 0, 470, 471, 472, 0, 0, - 473, 474, 475, 476, 477, 0, 478, 479, 480, 481, - 482, 483, 484, 485, 0, 0, 486, 487, 488, 0, + 404, 405, 406, 407, 408, 0, 409, 410, 1576, 412, + 413, 414, 1577, 416, 417, 418, 419, 420, 421, 422, + 423, 424, 425, 426, 427, 428, 0, 1578, 429, 430, + 431, 432, 433, 434, 1579, 436, 437, 0, 1580, 439, + 440, 1581, 442, 0, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 456, 1582, 458, + 0, 0, 0, 460, 461, 0, 462, 1583, 464, 465, + 466, 467, 468, 469, 0, 470, 1584, 1585, 0, 0, + 473, 474, 0, 476, 0, 0, 478, 479, 1586, 481, + 482, 483, 484, 485, 1587, 0, 486, 487, 488, 1588, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, - 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, - 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, - 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, - 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 122, 123, 124, 125, 126, 127, 128, 129, 968, 130, - 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, - 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, - 150, 151, 152, 0, 0, 153, 154, 155, 156, 157, - 158, 159, 0, 160, 161, 162, 163, 164, 0, 0, - 0, 166, 167, 168, 169, 170, 171, 0, 173, 174, - 175, 0, 176, 177, 178, 179, 180, 181, 0, 0, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 0, 198, 0, 199, 200, - 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, - 0, 0, 209, 210, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 0, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 0, - 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, - 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, - 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, - 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, - 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, - 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, - 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, - 292, 293, 0, 0, 294, 0, 296, 0, 0, 298, - 299, 300, 301, 302, 303, 304, 305, 541, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, - 329, 0, 331, 332, 333, 334, 335, 0, 336, 337, - 0, 339, 0, 340, 341, 342, 343, 344, 345, 0, - 346, 347, 0, 0, 348, 349, 350, 0, 0, 351, - 352, 353, 0, 355, 0, 357, 358, 359, 360, 361, - 362, 363, 364, 365, 366, 367, 368, 369, 0, 0, - 0, 0, 370, 371, 372, 0, 374, 375, 376, 377, - 378, 379, 0, 380, 381, 382, 383, 384, 385, 0, - 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, - 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 0, 409, 410, 0, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, - 424, 425, 426, 427, 428, 0, 0, 429, 430, 431, - 432, 433, 434, 435, 436, 437, 0, 0, 439, 440, - 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, - 450, 451, 452, 453, 454, 455, 456, 542, 458, 459, - 0, 0, 460, 461, 0, 462, 0, 464, 465, 466, - 467, 468, 469, 0, 470, 471, 472, 0, 0, 473, - 474, 475, 476, 477, 0, 478, 479, 480, 481, 482, - 483, 484, 485, 0, 0, 486, 487, 488, 0, 0, - 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, - 498, 499, 500, 0, 501, 0, 503, 504, 505, 506, - 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, - 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, - 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, - 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, - 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, - 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, - 151, 152, 0, 0, 153, 154, 155, 156, 157, 158, - 159, 0, 160, 161, 162, 163, 164, 0, 0, 0, - 166, 167, 168, 169, 170, 171, 0, 173, 174, 175, - 0, 176, 177, 178, 179, 180, 181, 0, 0, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 0, 198, 0, 199, 200, 201, - 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, - 0, 209, 210, 211, 212, 213, 0, 214, 215, 216, - 0, 217, 218, 219, 220, 0, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 1207, 231, 232, 0, 233, - 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, - 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, - 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, - 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, - 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, - 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, - 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, - 293, 0, 0, 294, 0, 296, 0, 0, 298, 299, - 300, 301, 302, 303, 304, 305, 541, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, - 0, 331, 332, 333, 334, 335, 0, 336, 337, 0, - 339, 0, 340, 341, 342, 343, 344, 345, 0, 346, - 347, 0, 811, 348, 349, 350, 0, 0, 351, 352, - 353, 0, 355, 0, 357, 358, 359, 360, 361, 362, - 363, 364, 365, 366, 367, 368, 369, 0, 0, 0, - 0, 370, 371, 372, 0, 374, 375, 376, 377, 378, - 379, 0, 380, 381, 382, 383, 384, 385, 0, 386, - 387, 388, 389, 390, 391, 392, 393, 394, 395, 0, - 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 0, 409, 410, 0, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 0, 0, 429, 430, 431, 432, - 433, 434, 435, 436, 437, 0, 0, 439, 440, 441, - 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, - 451, 452, 453, 454, 455, 456, 542, 458, 459, 0, - 0, 460, 461, 0, 462, 0, 464, 465, 466, 467, - 468, 469, 0, 470, 471, 472, 0, 0, 473, 474, - 475, 476, 477, 0, 478, 479, 480, 481, 482, 483, - 484, 485, 0, 0, 486, 487, 488, 0, 0, 489, - 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, - 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, - 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, - 524, 525, 526, 527, 528, 529, 530, 531, 1534, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, - 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, - 0, 0, 0, 1535, 0, 0, 0, 0, 1536, 134, - 135, 0, 1537, 137, 138, 1538, 140, 141, 142, 0, - 1539, 1540, 1541, 1542, 0, 1543, 148, 149, 150, 151, - 152, 0, 0, 153, 154, 155, 156, 1544, 1545, 159, - 0, 160, 161, 162, 163, 0, 0, 1546, 0, 1547, - 167, 168, 169, 170, 171, 1548, 173, 174, 175, 0, - 176, 177, 178, 179, 180, 181, 0, 1549, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 1550, 194, - 195, 1551, 197, 0, 198, 0, 199, 200, 201, 202, - 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, - 209, 210, 1093, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 0, 221, 222, 223, 224, 0, - 226, 227, 228, 229, 230, 231, 0, 0, 233, 0, - 234, 235, 1552, 237, 0, 238, 0, 239, 1553, 0, - 1554, 242, 243, 0, 1555, 246, 247, 248, 0, 0, - 0, 251, 252, 0, 253, 254, 255, 256, 257, 258, - 259, 1556, 261, 262, 263, 264, 0, 265, 266, 267, - 268, 269, 270, 271, 0, 272, 1557, 0, 275, 276, - 277, 278, 279, 1558, 1559, 0, 1560, 0, 283, 1561, - 1562, 286, 1563, 288, 289, 290, 0, 291, 292, 293, - 0, 0, 294, 1564, 296, 1565, 0, 298, 299, 300, - 301, 302, 303, 304, 305, 1566, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, 1567, 1568, - 1569, 332, 333, 334, 0, 0, 336, 337, 1570, 339, - 0, 0, 341, 1571, 343, 344, 345, 0, 346, 347, - 0, 0, 348, 349, 350, 0, 0, 351, 352, 0, - 1572, 355, 1573, 0, 358, 359, 360, 361, 362, 363, - 364, 365, 366, 367, 368, 369, 0, 0, 0, 0, - 370, 371, 0, 1574, 374, 375, 0, 377, 378, 379, - 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, - 388, 389, 390, 1575, 392, 393, 394, 395, 0, 396, - 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 0, 409, 410, 1576, 412, 413, 414, 1577, - 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 0, 1578, 429, 430, 431, 432, 433, - 434, 1579, 436, 437, 0, 1580, 439, 440, 1581, 442, - 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, - 452, 453, 454, 455, 456, 1582, 458, 0, 0, 0, - 460, 461, 0, 462, 1583, 464, 465, 466, 467, 468, - 469, 0, 470, 1584, 1585, 0, 0, 473, 474, 0, - 476, 0, 0, 478, 479, 1586, 481, 482, 483, 484, - 485, 1587, 0, 486, 487, 488, 1588, 0, 489, 490, - 491, 492, 0, 493, 494, 495, 496, 497, 0, 1589, - 500, 0, 501, 1590, 503, 504, 505, 506, 507, 508, - 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, - 515, 516, 539, 0, 564, 0, 0, 0, 0, 0, - 0, 0, 0, 528, 529, 530, 531, 0, 0, 0, - 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, - 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, - 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, - 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, - 156, 157, 158, 159, 0, 160, 161, 162, 163, 164, - 0, 0, 0, 166, 167, 168, 169, 170, 171, 0, - 173, 174, 175, 0, 176, 177, 178, 179, 180, 181, - 0, 0, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 0, 198, 0, - 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, - 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, - 0, 239, 0, 0, 0, 242, 243, 540, 0, 2042, - 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, - 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, - 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, - 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, - 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, - 0, 291, 292, 293, 0, 0, 294, 0, 296, 0, - 0, 298, 299, 2043, 301, 302, 303, 304, 305, 541, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 329, 0, 331, 332, 333, 334, 335, 0, - 336, 337, 0, 339, 0, 340, 341, 342, 343, 344, - 345, 0, 346, 347, 0, 0, 348, 349, 350, 0, - 0, 351, 352, 353, 0, 355, 0, 357, 358, 359, - 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, - 0, 0, 0, 0, 370, 371, 372, 0, 374, 375, - 376, 377, 378, 379, 0, 380, 381, 382, 383, 384, - 385, 0, 386, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 0, 409, 410, 0, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, - 430, 431, 432, 433, 434, 435, 436, 437, 0, 0, - 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, - 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, - 458, 459, 0, 0, 460, 461, 2044, 462, 0, 464, - 465, 2045, 467, 2046, 469, 0, 470, 471, 472, 0, - 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, - 481, 482, 483, 484, 485, 0, 0, 486, 487, 2047, - 0, 0, 489, 490, 491, 492, 0, 493, 494, 495, - 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, - 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, - 531, 1534, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, - 130, 131, 132, 0, 0, 0, 1535, 0, 0, 0, - 0, 1536, 134, 135, 0, 1537, 137, 138, 1538, 140, - 141, 142, 0, 1539, 1540, 1541, 1542, 0, 1543, 148, - 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, - 1544, 1545, 159, 0, 160, 161, 162, 163, 0, 0, - 1546, 0, 1547, 167, 168, 169, 170, 171, 1548, 173, - 174, 175, 0, 176, 177, 178, 179, 180, 181, 0, - 1549, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 1550, 194, 195, 1551, 197, 0, 198, 0, 199, - 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, - 208, 0, 0, 209, 210, 1093, 212, 213, 0, 214, - 215, 216, 0, 2454, 218, 219, 220, 0, 221, 222, - 223, 224, 0, 226, 227, 228, 229, 230, 231, 0, - 0, 233, 0, 234, 235, 1552, 237, 0, 238, 0, - 239, 1553, 0, 1554, 242, 243, 0, 1555, 246, 247, - 248, 0, 0, 0, 251, 252, 0, 253, 254, 255, - 256, 257, 258, 259, 1556, 261, 262, 263, 264, 0, - 265, 266, 267, 268, 269, 270, 271, 0, 272, 1557, - 0, 275, 276, 277, 278, 279, 1558, 1559, 0, 1560, - 0, 283, 1561, 1562, 286, 1563, 288, 289, 290, 0, - 291, 292, 293, 0, 0, 294, 1564, 296, 1565, 0, - 298, 299, 300, 301, 302, 303, 304, 305, 1566, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, - 328, 1567, 1568, 1569, 332, 333, 334, 0, 0, 336, - 337, 1570, 339, 0, 0, 341, 1571, 343, 344, 345, - 0, 346, 347, 0, 0, 348, 349, 350, 0, 0, - 351, 352, 0, 1572, 355, 1573, 0, 358, 359, 360, - 361, 362, 363, 364, 365, 366, 367, 368, 369, 0, - 0, 0, 0, 370, 371, 0, 1574, 374, 375, 0, - 377, 378, 379, 0, 380, 381, 382, 383, 384, 385, - 0, 386, 387, 388, 389, 390, 1575, 392, 393, 394, - 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 0, 409, 410, 1576, 412, - 413, 414, 1577, 416, 417, 418, 419, 420, 421, 422, - 423, 424, 425, 426, 427, 428, 0, 1578, 429, 430, - 431, 432, 433, 434, 1579, 436, 437, 0, 1580, 439, - 440, 1581, 442, 0, 443, 444, 445, 446, 447, 448, - 449, 450, 451, 452, 453, 454, 455, 456, 1582, 458, - 0, 0, 0, 460, 461, 0, 462, 1583, 464, 465, - 466, 467, 468, 469, 0, 470, 1584, 1585, 0, 0, - 473, 474, 0, 476, 0, 0, 478, 479, 1586, 481, - 482, 483, 484, 485, 1587, 0, 486, 487, 488, 1588, - 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, - 497, 0, 1589, 500, 0, 501, 1590, 503, 504, 505, + 497, 0, 1589, 500, 0, 501, 1590, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 528, 529, 530, 531, @@ -10535,13 +10473,13 @@ static const yytype_int16 yytable[] = 220, 0, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, - 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, + 540, 0, 2042, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, 293, 0, 0, 294, - 0, 296, 0, 0, 298, 299, 300, 301, 302, 303, + 0, 296, 0, 0, 298, 299, 2043, 301, 302, 303, 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, @@ -10559,70 +10497,323 @@ static const yytype_int16 yytable[] = 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, - 462, 0, 464, 465, 466, 467, 468, 469, 0, 470, + 455, 456, 542, 458, 459, 0, 0, 460, 461, 2044, + 462, 0, 464, 465, 2045, 467, 2046, 469, 0, 470, 471, 472, 0, 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, - 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, + 486, 487, 2047, 0, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, - 528, 529, 530, 531, 539, 0, 836, 0, 0, 0, + 528, 529, 530, 531, 1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, - 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, - 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, - 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, - 154, 155, 156, 157, 158, 159, 0, 160, 161, 162, - 163, 164, 0, 0, 0, 166, 167, 168, 169, 170, - 171, 0, 173, 174, 175, 0, 176, 177, 178, 179, - 180, 181, 0, 0, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 0, + 128, 129, 0, 130, 131, 132, 0, 0, 0, 1535, + 0, 0, 0, 0, 1536, 134, 135, 0, 1537, 137, + 138, 1538, 140, 141, 142, 0, 1539, 1540, 1541, 1542, + 0, 1543, 148, 149, 150, 151, 152, 0, 0, 153, + 154, 155, 156, 1544, 1545, 159, 0, 160, 161, 162, + 163, 0, 0, 1546, 0, 1547, 167, 168, 169, 170, + 171, 1548, 173, 174, 175, 0, 176, 177, 178, 179, + 180, 181, 0, 1549, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 1550, 194, 195, 1551, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, - 205, 206, 207, 208, 0, 0, 209, 210, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 0, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, - 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, - 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, - 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, + 205, 206, 207, 208, 0, 0, 209, 210, 1093, 212, + 213, 0, 214, 215, 216, 0, 2455, 218, 219, 220, + 0, 221, 222, 223, 224, 0, 226, 227, 228, 229, + 230, 231, 0, 0, 233, 0, 234, 235, 1552, 237, + 0, 238, 0, 239, 1553, 0, 1554, 242, 243, 0, + 1555, 246, 247, 248, 0, 0, 0, 251, 252, 0, + 253, 254, 255, 256, 257, 258, 259, 1556, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, - 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, - 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, - 289, 290, 0, 291, 292, 293, 0, 0, 294, 0, - 296, 0, 0, 298, 299, 300, 301, 302, 303, 304, - 305, 541, 307, 308, 309, 310, 311, 312, 313, 314, + 0, 272, 1557, 0, 275, 276, 277, 278, 279, 1558, + 1559, 0, 1560, 0, 283, 1561, 1562, 286, 1563, 288, + 289, 290, 0, 291, 292, 293, 0, 0, 294, 1564, + 296, 1565, 0, 298, 299, 300, 301, 302, 303, 304, + 305, 1566, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 0, 331, 332, 333, 334, - 335, 0, 336, 337, 0, 339, 0, 340, 341, 342, + 325, 326, 327, 328, 1567, 1568, 1569, 332, 333, 334, + 0, 0, 336, 337, 1570, 339, 0, 0, 341, 1571, 343, 344, 345, 0, 346, 347, 0, 0, 348, 349, - 350, 0, 0, 351, 352, 353, 0, 355, 0, 357, + 350, 0, 0, 351, 352, 0, 1572, 355, 1573, 0, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, - 368, 369, 0, 0, 0, 0, 370, 371, 372, 0, - 374, 375, 376, 377, 378, 379, 0, 380, 381, 382, - 383, 384, 385, 0, 386, 387, 388, 389, 390, 391, + 368, 369, 0, 0, 0, 0, 370, 371, 0, 1574, + 374, 375, 0, 377, 378, 379, 0, 380, 381, 382, + 383, 384, 385, 0, 386, 387, 388, 389, 390, 1575, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, - 410, 0, 412, 413, 414, 415, 416, 417, 418, 419, + 410, 1576, 412, 413, 414, 1577, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, - 0, 429, 430, 431, 432, 433, 434, 435, 436, 437, - 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, + 1578, 429, 430, 431, 432, 433, 434, 1579, 436, 437, + 0, 1580, 439, 440, 1581, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, - 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, - 0, 464, 465, 466, 467, 468, 469, 0, 470, 471, - 472, 0, 0, 473, 474, 475, 476, 477, 0, 478, - 479, 480, 481, 482, 483, 484, 485, 0, 0, 486, - 487, 488, 0, 0, 489, 490, 491, 492, 0, 493, - 494, 495, 496, 497, 498, 499, 500, 0, 501, 0, + 456, 1582, 458, 0, 0, 0, 460, 461, 0, 462, + 1583, 464, 465, 466, 467, 468, 469, 0, 470, 1584, + 1585, 0, 0, 473, 474, 0, 476, 0, 0, 478, + 479, 1586, 481, 482, 483, 484, 485, 1587, 0, 486, + 487, 488, 1588, 0, 489, 490, 491, 492, 0, 493, + 494, 495, 496, 497, 0, 1589, 500, 0, 501, 1590, + 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, + 0, 0, 511, 512, 513, 514, 515, 516, 539, 0, + 564, 0, 0, 0, 0, 0, 0, 0, 0, 528, + 529, 530, 531, 0, 0, 0, 0, 0, 122, 123, + 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, + 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, + 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, + 152, 0, 0, 153, 154, 155, 156, 157, 158, 159, + 0, 160, 161, 162, 163, 164, 0, 0, 0, 166, + 167, 168, 169, 170, 171, 0, 173, 174, 175, 0, + 176, 177, 178, 179, 180, 181, 0, 0, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 0, 198, 0, 199, 200, 201, 202, + 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, + 209, 210, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 0, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 0, 233, 0, + 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, + 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, + 250, 251, 252, 0, 253, 254, 255, 256, 257, 258, + 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, + 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, + 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, + 0, 286, 0, 288, 289, 290, 0, 291, 292, 293, + 0, 0, 294, 0, 296, 0, 0, 298, 299, 300, + 301, 302, 303, 304, 305, 541, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328, 329, 0, + 331, 332, 333, 334, 335, 0, 336, 337, 0, 339, + 0, 340, 341, 342, 343, 344, 345, 0, 346, 347, + 0, 0, 348, 349, 350, 0, 0, 351, 352, 353, + 0, 355, 0, 357, 358, 359, 360, 361, 362, 363, + 364, 365, 366, 367, 368, 369, 0, 0, 0, 0, + 370, 371, 372, 0, 374, 375, 376, 377, 378, 379, + 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, + 388, 389, 390, 391, 392, 393, 394, 395, 0, 396, + 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 0, 409, 410, 0, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, + 426, 427, 428, 0, 0, 429, 430, 431, 432, 433, + 434, 435, 436, 437, 0, 0, 439, 440, 441, 442, + 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, + 452, 453, 454, 455, 456, 542, 458, 459, 0, 0, + 460, 461, 0, 462, 0, 464, 465, 466, 467, 468, + 469, 0, 470, 471, 472, 0, 0, 473, 474, 475, + 476, 477, 0, 478, 479, 480, 481, 482, 483, 484, + 485, 0, 0, 486, 487, 488, 0, 0, 489, 490, + 491, 492, 0, 493, 494, 495, 496, 497, 498, 499, + 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, + 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, + 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, + 525, 526, 527, 528, 529, 530, 531, 539, 0, 836, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, + 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, + 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, + 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, + 0, 0, 153, 154, 155, 156, 157, 158, 159, 0, + 160, 161, 162, 163, 164, 0, 0, 0, 166, 167, + 168, 169, 170, 171, 0, 173, 174, 175, 0, 176, + 177, 178, 179, 180, 181, 0, 0, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 0, 198, 0, 199, 200, 201, 202, 203, + 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, + 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 0, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, + 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, + 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, + 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, + 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, + 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, + 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, + 286, 0, 288, 289, 290, 0, 291, 292, 293, 0, + 0, 294, 0, 296, 0, 0, 298, 299, 300, 301, + 302, 303, 304, 305, 541, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, 327, 328, 329, 0, 331, + 332, 333, 334, 335, 0, 336, 337, 0, 339, 0, + 340, 341, 342, 343, 344, 345, 0, 346, 347, 0, + 0, 348, 349, 350, 0, 0, 351, 352, 353, 0, + 355, 0, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 0, 0, 0, 0, 370, + 371, 372, 0, 374, 375, 376, 377, 378, 379, 0, + 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, + 389, 390, 391, 392, 393, 394, 395, 0, 396, 397, + 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 0, 409, 410, 0, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, + 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 0, 0, 439, 440, 441, 442, 0, + 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, + 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, + 461, 0, 462, 0, 464, 465, 466, 467, 468, 469, + 0, 470, 471, 472, 0, 0, 473, 474, 475, 476, + 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, + 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, + 492, 0, 493, 494, 495, 496, 497, 498, 499, 500, + 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, + 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, + 526, 527, 528, 529, 530, 531, 539, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, + 126, 127, 128, 129, 842, 130, 131, 132, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, + 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, + 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, + 0, 153, 154, 155, 156, 157, 158, 159, 0, 160, + 161, 162, 163, 164, 0, 0, 0, 166, 167, 168, + 169, 170, 171, 0, 173, 174, 175, 0, 176, 177, + 178, 179, 180, 181, 0, 0, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, + 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 0, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, + 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, + 243, 540, 0, 843, 247, 248, 0, 249, 250, 251, + 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, + 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, + 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, + 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, + 0, 288, 289, 290, 0, 291, 292, 293, 0, 0, + 294, 0, 296, 0, 0, 298, 299, 844, 301, 302, + 303, 304, 305, 541, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 325, 326, 327, 328, 329, 0, 331, 332, + 333, 334, 335, 0, 336, 337, 0, 339, 0, 340, + 341, 342, 343, 344, 345, 0, 346, 347, 0, 0, + 348, 349, 350, 0, 0, 351, 352, 353, 0, 355, + 0, 357, 358, 359, 360, 361, 362, 363, 364, 365, + 366, 367, 368, 369, 0, 0, 0, 0, 370, 371, + 372, 0, 374, 375, 376, 377, 378, 379, 0, 380, + 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, + 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, + 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 0, 409, 410, 0, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, + 428, 0, 0, 429, 430, 431, 432, 845, 434, 435, + 436, 437, 0, 0, 439, 440, 441, 442, 0, 443, + 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, + 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, + 0, 462, 0, 464, 465, 466, 467, 468, 469, 0, + 470, 846, 472, 0, 0, 847, 474, 475, 476, 477, + 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, + 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, + 0, 493, 494, 495, 496, 497, 498, 499, 848, 0, + 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, + 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, + 527, 528, 529, 530, 531, 539, 0, 564, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, + 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, + 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, + 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, + 153, 154, 155, 156, 157, 158, 159, 0, 160, 161, + 162, 163, 164, 0, 0, 0, 166, 167, 168, 169, + 170, 171, 0, 173, 174, 175, 0, 176, 177, 178, + 179, 180, 181, 0, 0, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, + 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, + 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, + 220, 0, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, + 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, + 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, + 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, + 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, + 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, + 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, + 288, 289, 290, 0, 291, 292, 293, 0, 0, 294, + 0, 296, 0, 0, 298, 299, 300, 301, 302, 303, + 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, + 334, 335, 0, 336, 337, 0, 339, 0, 340, 341, + 342, 343, 344, 345, 0, 346, 347, 0, 0, 348, + 349, 350, 0, 0, 351, 352, 353, 0, 355, 0, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, + 367, 368, 369, 0, 0, 0, 0, 370, 371, 372, + 0, 374, 375, 376, 377, 378, 379, 0, 380, 381, + 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, + 391, 392, 393, 881, 395, 0, 396, 397, 398, 399, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, + 409, 410, 0, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, + 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, + 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, + 462, 0, 464, 465, 466, 467, 468, 469, 0, 470, + 471, 472, 0, 0, 473, 474, 475, 476, 477, 0, + 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, + 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, + 493, 494, 495, 496, 497, 498, 499, 500, 0, 501, + 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, + 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, + 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, + 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, + 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, + 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, + 154, 155, 156, 157, 158, 159, 0, 160, 161, 162, + 163, 164, 0, 0, 0, 166, 167, 168, 169, 170, + 171, 0, 173, 174, 175, 0, 176, 177, 178, 179, + 180, 181, 0, 0, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 0, + 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, + 205, 206, 207, 208, 0, 0, 209, 210, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 0, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, + 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, + 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, + 253, 254, 255, 256, 257, 918, 259, 0, 261, 262, + 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, + 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, + 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, + 289, 290, 0, 291, 292, 293, 0, 0, 294, 0, + 296, 0, 0, 298, 299, 300, 301, 302, 303, 304, + 305, 541, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 0, 331, 332, 333, 334, + 335, 0, 336, 337, 0, 339, 0, 340, 341, 342, + 343, 344, 345, 0, 346, 347, 0, 0, 348, 349, + 350, 0, 0, 351, 352, 353, 0, 355, 0, 357, + 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, + 368, 369, 0, 0, 0, 0, 370, 371, 372, 0, + 374, 375, 376, 377, 378, 379, 0, 380, 381, 382, + 383, 384, 385, 0, 386, 387, 388, 389, 390, 391, + 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, + 410, 0, 412, 413, 414, 415, 416, 417, 418, 419, + 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, + 0, 429, 430, 431, 432, 433, 434, 435, 436, 437, + 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, + 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, + 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, + 0, 464, 465, 466, 467, 468, 469, 0, 470, 471, + 472, 0, 0, 473, 474, 475, 476, 477, 0, 478, + 479, 480, 481, 482, 483, 484, 485, 0, 0, 486, + 487, 488, 0, 0, 489, 490, 491, 492, 0, 493, + 494, 495, 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, - 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, + 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, - 129, 842, 130, 131, 132, 0, 0, 0, 0, 0, + 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, @@ -10637,13 +10828,13 @@ static const yytype_int16 yytable[] = 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, - 843, 247, 248, 0, 249, 250, 251, 252, 0, 253, - 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, + 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, + 254, 255, 256, 257, 921, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, 293, 0, 0, 294, 0, 296, - 0, 0, 298, 299, 844, 301, 302, 303, 304, 305, + 0, 0, 298, 299, 300, 301, 302, 303, 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, 334, 335, @@ -10658,15 +10849,15 @@ static const yytype_int16 yytable[] = 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, 0, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, - 429, 430, 431, 432, 845, 434, 435, 436, 437, 0, + 429, 430, 431, 432, 433, 434, 435, 436, 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, 0, - 464, 465, 466, 467, 468, 469, 0, 470, 846, 472, - 0, 0, 847, 474, 475, 476, 477, 0, 478, 479, + 464, 465, 466, 467, 468, 469, 0, 470, 471, 472, + 0, 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, 493, 494, - 495, 496, 497, 498, 499, 848, 0, 501, 0, 503, + 495, 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, @@ -10689,7 +10880,7 @@ static const yytype_int16 yytable[] = 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, - 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, + 255, 256, 257, 925, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, @@ -10705,7 +10896,7 @@ static const yytype_int16 yytable[] = 0, 0, 0, 0, 370, 371, 372, 0, 374, 375, 376, 377, 378, 379, 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, 391, 392, 393, - 881, 395, 0, 396, 397, 398, 399, 400, 401, 402, + 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, 0, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, @@ -10740,7 +10931,7 @@ static const yytype_int16 yytable[] = 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, - 256, 257, 918, 259, 0, 261, 262, 263, 264, 0, + 256, 257, 956, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, @@ -10791,7 +10982,7 @@ static const yytype_int16 yytable[] = 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, - 257, 921, 259, 0, 261, 262, 263, 264, 0, 265, + 257, 984, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, @@ -10842,7 +11033,7 @@ static const yytype_int16 yytable[] = 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, - 925, 259, 0, 261, 262, 263, 264, 0, 265, 266, + 987, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, @@ -10874,10 +11065,10 @@ static const yytype_int16 yytable[] = 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, - 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, + 0, 0, 0, 0, 0, 0, 1030, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, 157, 158, 159, @@ -10892,7 +11083,7 @@ static const yytype_int16 yytable[] = 226, 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, - 250, 251, 252, 0, 253, 254, 255, 256, 257, 956, + 250, 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, @@ -10924,11 +11115,11 @@ static const yytype_int16 yytable[] = 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, - 525, 526, 527, 528, 529, 530, 531, 539, 0, 564, + 525, 526, 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, + 0, 0, 0, 0, 0, 1057, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, 157, 158, 159, 0, @@ -10943,7 +11134,7 @@ static const yytype_int16 yytable[] = 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, - 251, 252, 0, 253, 254, 255, 256, 257, 984, 259, + 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, @@ -10975,10 +11166,10 @@ static const yytype_int16 yytable[] = 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, - 526, 527, 528, 529, 530, 531, 539, 0, 564, 0, + 526, 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, - 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, + 126, 127, 128, 129, 842, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, @@ -10994,7 +11185,7 @@ static const yytype_int16 yytable[] = 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, - 252, 0, 253, 254, 255, 256, 257, 987, 259, 0, + 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, @@ -11019,18 +11210,18 @@ static const yytype_int16 yytable[] = 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, 0, 464, 465, 466, 467, 468, 469, 0, - 470, 471, 472, 0, 0, 473, 474, 475, 476, 477, + 470, 846, 472, 0, 0, 847, 474, 475, 476, 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, - 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, + 527, 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, - 0, 0, 0, 1030, 0, 0, 134, 135, 0, 0, + 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, 157, 158, 159, 0, 160, 161, @@ -11045,7 +11236,7 @@ static const yytype_int16 yytable[] = 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, - 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, + 0, 253, 254, 255, 256, 257, 1355, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, @@ -11077,11 +11268,11 @@ static const yytype_int16 yytable[] = 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, - 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, + 528, 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, - 0, 0, 1057, 0, 0, 134, 135, 0, 0, 137, + 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, 157, 158, 159, 0, 160, 161, 162, @@ -11096,7 +11287,7 @@ static const yytype_int16 yytable[] = 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, - 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, + 253, 254, 255, 256, 257, 1357, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, @@ -11128,10 +11319,10 @@ static const yytype_int16 yytable[] = 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, - 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, + 529, 530, 531, 539, 0, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, - 129, 842, 130, 131, 132, 0, 0, 0, 0, 0, + 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, @@ -11147,7 +11338,7 @@ static const yytype_int16 yytable[] = 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, - 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, + 254, 255, 256, 257, 1360, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, @@ -11171,8 +11362,8 @@ static const yytype_int16 yytable[] = 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, 0, - 464, 465, 466, 467, 468, 469, 0, 470, 846, 472, - 0, 0, 847, 474, 475, 476, 477, 0, 478, 479, + 464, 465, 466, 467, 468, 469, 0, 470, 471, 472, + 0, 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, 499, 500, 0, 501, 0, 503, @@ -11198,7 +11389,7 @@ static const yytype_int16 yytable[] = 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, - 255, 256, 257, 1355, 259, 0, 261, 262, 263, 264, + 255, 256, 257, 1362, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, @@ -11249,7 +11440,7 @@ static const yytype_int16 yytable[] = 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, - 256, 257, 1357, 259, 0, 261, 262, 263, 264, 0, + 256, 257, 1364, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, @@ -11300,7 +11491,7 @@ static const yytype_int16 yytable[] = 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, - 257, 1360, 259, 0, 261, 262, 263, 264, 0, 265, + 257, 2347, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, @@ -11351,7 +11542,7 @@ static const yytype_int16 yytable[] = 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, - 1362, 259, 0, 261, 262, 263, 264, 0, 265, 266, + 3144, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, @@ -11383,7 +11574,7 @@ static const yytype_int16 yytable[] = 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 539, 0, - 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, @@ -11401,7 +11592,7 @@ static const yytype_int16 yytable[] = 226, 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, - 250, 251, 252, 0, 253, 254, 255, 256, 257, 1364, + 250, 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, @@ -11433,7 +11624,7 @@ static const yytype_int16 yytable[] = 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, - 525, 526, 527, 528, 529, 530, 531, 539, 0, 564, + 525, 526, 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, @@ -11451,13 +11642,13 @@ static const yytype_int16 yytable[] = 218, 219, 220, 0, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, - 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, - 251, 252, 0, 253, 254, 255, 256, 257, 2345, 259, + 242, 243, 540, 0, 858, 247, 248, 0, 249, 250, + 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, 293, 0, - 0, 294, 0, 296, 0, 0, 298, 299, 300, 301, + 0, 294, 0, 296, 0, 0, 298, 299, 859, 301, 302, 303, 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 0, 331, @@ -11471,20 +11662,20 @@ static const yytype_int16 yytable[] = 389, 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, 0, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, - 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, + 417, 418, 419, 860, 421, 422, 423, 424, 425, 426, + 427, 428, 0, 0, 429, 430, 431, 432, 861, 434, 435, 436, 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, 0, 464, 465, 466, 467, 468, 469, - 0, 470, 471, 472, 0, 0, 473, 474, 475, 476, + 0, 470, 862, 472, 0, 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, - 492, 0, 493, 494, 495, 496, 497, 498, 499, 500, + 492, 0, 493, 494, 495, 496, 497, 498, 499, 863, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, - 526, 527, 528, 529, 530, 531, 539, 0, 564, 0, + 526, 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, @@ -11503,7 +11694,7 @@ static const yytype_int16 yytable[] = 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, - 252, 0, 253, 254, 255, 256, 257, 3185, 259, 0, + 252, 0, 253, 254, 255, 256, 257, 916, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, @@ -11554,7 +11745,7 @@ static const yytype_int16 yytable[] = 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, - 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, + 0, 253, 254, 255, 256, 257, 980, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, @@ -11604,13 +11795,13 @@ static const yytype_int16 yytable[] = 0, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, - 0, 858, 247, 248, 0, 249, 250, 251, 252, 0, + 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, 293, 0, 0, 294, 0, - 296, 0, 0, 298, 299, 859, 301, 302, 303, 304, + 296, 0, 0, 298, 299, 300, 301, 302, 303, 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, 334, @@ -11625,7 +11816,7 @@ static const yytype_int16 yytable[] = 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, 0, 412, 413, 414, 415, 416, 417, 418, 419, 860, 421, 422, 423, 424, 425, 426, 427, 428, 0, - 0, 429, 430, 431, 432, 861, 434, 435, 436, 437, + 0, 429, 430, 431, 432, 433, 434, 435, 436, 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, @@ -11633,7 +11824,7 @@ static const yytype_int16 yytable[] = 472, 0, 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, 493, - 494, 495, 496, 497, 498, 499, 863, 0, 501, 0, + 494, 495, 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, @@ -11656,7 +11847,7 @@ static const yytype_int16 yytable[] = 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, - 254, 255, 256, 257, 916, 259, 0, 261, 262, 263, + 254, 255, 256, 257, 1351, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, @@ -11707,7 +11898,7 @@ static const yytype_int16 yytable[] = 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, - 255, 256, 257, 980, 259, 0, 261, 262, 263, 264, + 255, 256, 257, 1374, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, @@ -11742,7 +11933,7 @@ static const yytype_int16 yytable[] = 531, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, - 130, 131, 132, 0, 0, 0, 0, 0, 0, 0, + 130, 131, 132, 0, 0, 0, 0, 0, 0, 1735, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, @@ -11776,13 +11967,13 @@ static const yytype_int16 yytable[] = 0, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, 410, 0, 412, - 413, 414, 415, 416, 417, 418, 419, 860, 421, 422, + 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, 430, - 431, 432, 433, 434, 435, 436, 437, 0, 0, 439, + 431, 432, 433, 0, 435, 436, 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, 0, 464, 465, - 466, 467, 468, 469, 0, 470, 862, 472, 0, 0, + 466, 467, 468, 469, 0, 470, 471, 472, 0, 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, @@ -11809,7 +12000,7 @@ static const yytype_int16 yytable[] = 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, - 257, 1351, 259, 0, 261, 262, 263, 264, 0, 265, + 257, 1937, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, @@ -11860,7 +12051,7 @@ static const yytype_int16 yytable[] = 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, 0, 253, 254, 255, 256, 257, - 1374, 259, 0, 261, 262, 263, 264, 0, 265, 266, + 2329, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, @@ -11895,7 +12086,7 @@ static const yytype_int16 yytable[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, - 0, 0, 0, 0, 0, 0, 1735, 0, 0, 134, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, 157, 158, 159, @@ -11910,7 +12101,7 @@ static const yytype_int16 yytable[] = 226, 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, 249, - 250, 251, 252, 0, 253, 254, 255, 256, 257, 258, + 250, 251, 252, 0, 253, 254, 255, 256, 257, 2349, 259, 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, 0, @@ -11931,7 +12122,7 @@ static const yytype_int16 yytable[] = 407, 408, 0, 409, 410, 0, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, 430, 431, 432, 433, - 0, 435, 436, 437, 0, 0, 439, 440, 441, 442, + 434, 435, 436, 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, 462, 0, 464, 465, 466, 467, 468, @@ -11942,1464 +12133,1347 @@ static const yytype_int16 yytable[] = 500, 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, - 525, 526, 527, 528, 529, 530, 531, 539, 0, 0, + 525, 526, 527, 528, 529, 530, 531, 3483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 134, 135, - 0, 0, 137, 138, 0, 140, 141, 142, 143, 144, - 0, 146, 147, 0, 0, 148, 149, 150, 151, 152, - 0, 0, 153, 154, 155, 156, 157, 158, 159, 0, - 160, 161, 162, 163, 164, 0, 0, 0, 166, 167, - 168, 169, 170, 171, 0, 173, 174, 175, 0, 176, - 177, 178, 179, 180, 181, 0, 0, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 0, 198, 0, 199, 200, 201, 202, 203, + 0, 0, 3484, 0, 0, 0, 0, 3485, 134, 135, + 0, 3486, 137, 138, 3487, 140, 141, 142, 0, 1539, + 3488, 1541, 1542, 0, 3489, 148, 149, 150, 151, 152, + 0, 0, 153, 154, 155, 156, 1544, 1545, 159, 0, + 160, 161, 162, 163, 0, 0, 3490, 0, 3491, 167, + 168, 169, 170, 171, 3492, 173, 174, 175, 0, 176, + 177, 178, 179, 180, 181, 0, 3493, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 1550, 194, 195, + 1551, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, 209, - 210, 211, 212, 213, 0, 214, 215, 216, 0, 217, - 218, 219, 220, 0, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 0, 233, 0, 234, - 235, 236, 237, 0, 238, 0, 239, 0, 0, 0, - 242, 243, 540, 0, 246, 247, 248, 0, 249, 250, - 251, 252, 0, 253, 254, 255, 256, 257, 1937, 259, - 0, 261, 262, 263, 264, 0, 265, 266, 267, 268, - 269, 270, 271, 0, 272, 0, 274, 275, 276, 277, - 278, 279, 280, 281, 0, 282, 0, 283, 0, 0, - 286, 0, 288, 289, 290, 0, 291, 292, 293, 0, - 0, 294, 0, 296, 0, 0, 298, 299, 300, 301, - 302, 303, 304, 305, 541, 307, 308, 309, 310, 311, + 210, 1093, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 0, 221, 222, 223, 224, 0, 226, + 227, 228, 229, 230, 231, 0, 0, 233, 0, 234, + 235, 1552, 237, 0, 238, 0, 239, 3494, 0, 3495, + 242, 243, 2473, 3496, 246, 247, 248, 0, 0, 0, + 251, 252, 0, 253, 254, 255, 256, 257, 258, 259, + 3497, 261, 262, 263, 264, 0, 265, 266, 267, 268, + 269, 270, 271, 0, 272, 3498, 0, 275, 276, 277, + 278, 279, 1558, 1559, 0, 1560, 0, 283, 3499, 3500, + 286, 3501, 288, 289, 290, 0, 291, 292, 293, 0, + 0, 294, 3502, 296, 3503, 0, 298, 299, 300, 301, + 302, 303, 304, 305, 2482, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, 329, 0, 331, - 332, 333, 334, 335, 0, 336, 337, 0, 339, 0, - 340, 341, 342, 343, 344, 345, 0, 346, 347, 0, - 0, 348, 349, 350, 0, 0, 351, 352, 353, 0, - 355, 0, 357, 358, 359, 360, 361, 362, 363, 364, + 322, 323, 324, 325, 326, 327, 328, 1567, 3505, 1569, + 332, 333, 334, 0, 0, 336, 337, 3507, 339, 0, + 0, 341, 1571, 343, 344, 345, 0, 346, 347, 0, + 0, 348, 349, 350, 0, 0, 351, 352, 0, 3509, + 355, 3510, 0, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 0, 0, 0, 0, 370, - 371, 372, 0, 374, 375, 376, 377, 378, 379, 0, + 371, 0, 3511, 374, 375, 0, 377, 378, 379, 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, - 389, 390, 391, 392, 393, 394, 395, 0, 396, 397, + 389, 390, 1575, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 0, 409, 410, 0, 412, 413, 414, 415, 416, + 408, 0, 409, 410, 3512, 412, 413, 414, 0, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, - 427, 428, 0, 0, 429, 430, 431, 432, 433, 434, - 435, 436, 437, 0, 0, 439, 440, 441, 442, 0, + 427, 428, 0, 3513, 429, 430, 431, 432, 433, 434, + 0, 436, 437, 0, 3515, 439, 440, 1581, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, - 453, 454, 455, 456, 542, 458, 459, 0, 0, 460, - 461, 0, 462, 0, 464, 465, 466, 467, 468, 469, - 0, 470, 471, 472, 0, 0, 473, 474, 475, 476, - 477, 0, 478, 479, 480, 481, 482, 483, 484, 485, - 0, 0, 486, 487, 488, 0, 0, 489, 490, 491, - 492, 0, 493, 494, 495, 496, 497, 498, 499, 500, - 0, 501, 0, 503, 504, 505, 506, 507, 508, 509, + 453, 454, 455, 456, 2490, 458, 0, 0, 0, 460, + 461, 0, 462, 3517, 464, 465, 466, 467, 468, 469, + 0, 470, 1584, 1585, 0, 0, 473, 474, 0, 476, + 0, 0, 478, 479, 3518, 481, 482, 483, 484, 485, + 0, 0, 486, 487, 488, 3520, 0, 489, 490, 491, + 492, 0, 493, 494, 495, 496, 497, 0, 1589, 500, + 0, 501, 3521, 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, - 526, 527, 528, 529, 530, 531, 539, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 122, 123, 124, 125, - 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 134, 135, 0, - 0, 137, 138, 0, 140, 141, 142, 143, 144, 0, - 146, 147, 0, 0, 148, 149, 150, 151, 152, 0, - 0, 153, 154, 155, 156, 157, 158, 159, 0, 160, - 161, 162, 163, 164, 0, 0, 0, 166, 167, 168, - 169, 170, 171, 0, 173, 174, 175, 0, 176, 177, - 178, 179, 180, 181, 0, 0, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, - 0, 0, 205, 206, 207, 208, 0, 0, 209, 210, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 0, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 232, 0, 233, 0, 234, 235, - 236, 237, 0, 238, 0, 239, 0, 0, 0, 242, - 243, 540, 0, 246, 247, 248, 0, 249, 250, 251, - 252, 0, 253, 254, 255, 256, 257, 2327, 259, 0, - 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, - 270, 271, 0, 272, 0, 274, 275, 276, 277, 278, - 279, 280, 281, 0, 282, 0, 283, 0, 0, 286, - 0, 288, 289, 290, 0, 291, 292, 293, 0, 0, - 294, 0, 296, 0, 0, 298, 299, 300, 301, 302, - 303, 304, 305, 541, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, - 323, 324, 325, 326, 327, 328, 329, 0, 331, 332, - 333, 334, 335, 0, 336, 337, 0, 339, 0, 340, - 341, 342, 343, 344, 345, 0, 346, 347, 0, 0, - 348, 349, 350, 0, 0, 351, 352, 353, 0, 355, - 0, 357, 358, 359, 360, 361, 362, 363, 364, 365, - 366, 367, 368, 369, 0, 0, 0, 0, 370, 371, - 372, 0, 374, 375, 376, 377, 378, 379, 0, 380, - 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, - 390, 391, 392, 393, 394, 395, 0, 396, 397, 398, - 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, - 0, 409, 410, 0, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, - 428, 0, 0, 429, 430, 431, 432, 433, 434, 435, - 436, 437, 0, 0, 439, 440, 441, 442, 0, 443, - 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, - 454, 455, 456, 542, 458, 459, 0, 0, 460, 461, - 0, 462, 0, 464, 465, 466, 467, 468, 469, 0, - 470, 471, 472, 0, 0, 473, 474, 475, 476, 477, - 0, 478, 479, 480, 481, 482, 483, 484, 485, 0, - 0, 486, 487, 488, 0, 0, 489, 490, 491, 492, - 0, 493, 494, 495, 496, 497, 498, 499, 500, 0, - 501, 0, 503, 504, 505, 506, 507, 508, 509, 0, - 0, 510, 0, 0, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, - 527, 528, 529, 530, 531, 539, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 516, 1844, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 528, 529, 530, 531, 0, 0, 0, 0, + 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, + 130, 131, 132, 0, 0, 0, 1535, 0, 0, 0, + 0, 1536, 134, 135, 0, 1537, 137, 138, 1538, 140, + 141, 142, 0, 1539, 1540, 1541, 1542, 0, 1543, 148, + 149, 150, 151, 152, 0, 0, 153, 154, 155, 156, + 1544, 1545, 159, 0, 160, 161, 162, 163, 0, 0, + 1546, 0, 1547, 167, 168, 169, 170, 171, 1548, 173, + 174, 175, 0, 176, 177, 178, 179, 180, 181, 0, + 1549, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 1550, 194, 195, 1551, 197, 0, 198, 0, 199, + 200, 201, 202, 203, 204, 0, 0, 205, 206, 207, + 208, 0, 0, 209, 210, 1093, 212, 213, 0, 214, + 215, 216, 0, 217, 218, 219, 220, 0, 221, 222, + 223, 224, 0, 226, 227, 228, 229, 230, 231, 0, + 0, 233, 0, 234, 235, 1552, 237, 0, 238, 0, + 239, 1553, 0, 1554, 242, 243, 0, 1555, 246, 247, + 248, 0, 0, 0, 251, 252, 0, 253, 254, 255, + 256, 257, 258, 259, 1556, 261, 262, 263, 264, 0, + 265, 266, 267, 268, 269, 270, 271, 0, 272, 1557, + 0, 275, 276, 277, 278, 279, 1558, 1559, 0, 1560, + 0, 283, 1561, 1562, 286, 1563, 288, 289, 290, 0, + 291, 292, 293, 0, 0, 294, 1564, 296, 1565, 0, + 298, 299, 300, 301, 302, 303, 304, 305, 0, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, 1567, 1568, 1569, 332, 333, 334, 0, 0, 336, + 337, 1570, 339, 0, 0, 341, 1571, 343, 344, 345, + 0, 346, 347, 0, 0, 348, 349, 350, 0, 0, + 351, 352, 0, 1572, 355, 1573, 0, 358, 359, 360, + 361, 362, 363, 364, 365, 366, 367, 368, 369, 0, + 0, 0, 0, 370, 371, 0, 1574, 374, 375, 0, + 377, 378, 379, 0, 380, 381, 382, 383, 384, 385, + 0, 386, 387, 388, 389, 390, 1575, 392, 393, 394, + 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 0, 409, 410, 1576, 412, + 413, 414, 0, 416, 417, 418, 419, 420, 421, 422, + 423, 424, 425, 426, 427, 428, 0, 1578, 429, 430, + 431, 432, 433, 434, 0, 436, 437, 0, 1580, 439, + 440, 1581, 442, 0, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 456, 0, 458, + 0, 0, 0, 460, 461, 0, 462, 1583, 464, 465, + 466, 467, 468, 469, 0, 470, 1584, 1585, 0, 0, + 473, 474, 0, 476, 0, 0, 478, 479, 1586, 481, + 482, 483, 484, 485, 0, 0, 486, 487, 488, 1588, + 0, 489, 490, 491, 492, 0, 493, 494, 495, 496, + 497, 0, 1589, 500, 0, 501, 1590, 503, 504, 505, + 506, 507, 508, 509, 0, 0, 510, 0, 0, 511, + 512, 513, 514, 515, 516, 1534, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 528, 529, 530, 531, 0, 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 134, 135, 0, 0, - 137, 138, 0, 140, 141, 142, 143, 144, 0, 146, - 147, 0, 0, 148, 149, 150, 151, 152, 0, 0, - 153, 154, 155, 156, 157, 158, 159, 0, 160, 161, - 162, 163, 164, 0, 0, 0, 166, 167, 168, 169, - 170, 171, 0, 173, 174, 175, 0, 176, 177, 178, - 179, 180, 181, 0, 0, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 1535, 0, 0, 0, 0, 1536, 134, 135, 0, 1537, + 137, 138, 1538, 140, 141, 142, 0, 1539, 1540, 1541, + 1542, 0, 1543, 148, 149, 150, 151, 152, 0, 0, + 153, 154, 155, 156, 1544, 1545, 159, 0, 160, 161, + 162, 163, 0, 0, 1546, 0, 1547, 167, 168, 169, + 170, 171, 1548, 173, 174, 175, 0, 176, 177, 178, + 179, 180, 181, 0, 1549, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 1550, 194, 195, 1551, 197, 0, 198, 0, 199, 200, 201, 202, 203, 204, 0, - 0, 205, 206, 207, 208, 0, 0, 209, 210, 211, + 0, 205, 206, 207, 208, 0, 0, 209, 210, 1093, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 0, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 0, 233, 0, 234, 235, 236, - 237, 0, 238, 0, 239, 0, 0, 0, 242, 243, - 540, 0, 246, 247, 248, 0, 249, 250, 251, 252, - 0, 253, 254, 255, 256, 257, 2347, 259, 0, 261, + 220, 0, 221, 222, 223, 224, 0, 226, 227, 228, + 229, 230, 231, 0, 0, 233, 0, 234, 235, 1552, + 237, 0, 238, 0, 239, 1553, 0, 1554, 242, 243, + 0, 1555, 246, 247, 248, 0, 0, 0, 251, 252, + 0, 253, 254, 255, 256, 257, 258, 259, 1556, 261, 262, 263, 264, 0, 265, 266, 267, 268, 269, 270, - 271, 0, 272, 0, 274, 275, 276, 277, 278, 279, - 280, 281, 0, 282, 0, 283, 0, 0, 286, 0, + 271, 0, 272, 1557, 0, 275, 276, 277, 278, 279, + 1558, 1559, 0, 1560, 0, 283, 1561, 1562, 286, 1563, 288, 289, 290, 0, 291, 292, 293, 0, 0, 294, - 0, 296, 0, 0, 298, 299, 300, 301, 302, 303, - 304, 305, 541, 307, 308, 309, 310, 311, 312, 313, + 1564, 296, 1565, 0, 298, 299, 300, 301, 302, 303, + 304, 305, 0, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, - 324, 325, 326, 327, 328, 329, 0, 331, 332, 333, - 334, 335, 0, 336, 337, 0, 339, 0, 340, 341, - 342, 343, 344, 345, 0, 346, 347, 0, 0, 348, - 349, 350, 0, 0, 351, 352, 353, 0, 355, 0, - 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, - 367, 368, 369, 0, 0, 0, 0, 370, 371, 372, - 0, 374, 375, 376, 377, 378, 379, 0, 380, 381, + 324, 325, 326, 327, 328, 1567, 1568, 1569, 332, 333, + 334, 0, 0, 336, 337, 1570, 339, 0, 0, 341, + 1571, 343, 344, 345, 0, 346, 347, 0, 0, 348, + 349, 350, 0, 0, 351, 352, 0, 1572, 355, 1573, + 0, 358, 359, 360, 361, 362, 363, 364, 365, 366, + 367, 368, 369, 0, 0, 0, 0, 370, 371, 0, + 1574, 374, 375, 0, 377, 378, 379, 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, 388, 389, 390, - 391, 392, 393, 394, 395, 0, 396, 397, 398, 399, + 1575, 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 0, - 409, 410, 0, 412, 413, 414, 415, 416, 417, 418, + 409, 410, 1576, 412, 413, 414, 0, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, - 0, 0, 429, 430, 431, 432, 433, 434, 435, 436, - 437, 0, 0, 439, 440, 441, 442, 0, 443, 444, + 0, 1578, 429, 430, 431, 432, 433, 434, 0, 436, + 437, 0, 1580, 439, 440, 1581, 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 542, 458, 459, 0, 0, 460, 461, 0, - 462, 0, 464, 465, 466, 467, 468, 469, 0, 470, - 471, 472, 0, 0, 473, 474, 475, 476, 477, 0, - 478, 479, 480, 481, 482, 483, 484, 485, 0, 0, - 486, 487, 488, 0, 0, 489, 490, 491, 492, 0, - 493, 494, 495, 496, 497, 498, 499, 500, 0, 501, - 0, 503, 504, 505, 506, 507, 508, 509, 0, 0, - 510, 0, 0, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, - 528, 529, 530, 531, 3381, 0, 0, 0, 0, 0, + 455, 456, 0, 458, 0, 0, 0, 460, 461, 0, + 462, 1583, 464, 465, 466, 467, 468, 469, 0, 470, + 1584, 1585, 0, 0, 473, 474, 0, 476, 0, 0, + 478, 479, 1586, 481, 482, 483, 484, 485, 0, 0, + 486, 487, 488, 1588, 0, 489, 490, 491, 492, 0, + 493, 494, 495, 496, 497, 0, 1589, 500, 0, 501, + 1590, 503, 504, 505, 506, 507, 508, 509, 0, 0, + 510, 0, 0, 511, 512, 513, 514, 515, 516, 539, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 528, 529, 530, 531, 0, 0, 0, 0, 0, 122, + 123, 124, 125, 126, 127, 128, 129, 0, 130, 131, + 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 134, 135, 0, 0, 137, 138, 0, 140, 141, 142, + 143, 144, 0, 146, 147, 0, 0, 148, 149, 150, + 151, 152, 0, 0, 153, 154, 155, 156, 157, 158, + 159, 0, 160, 161, 162, 163, 164, 0, 0, 0, + 166, 167, 168, 169, 170, 171, 0, 173, 174, 175, + 0, 176, 177, 178, 179, 180, 181, 0, 0, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 0, 198, 0, 199, 200, 201, + 202, 203, 204, 0, 0, 205, 206, 207, 208, 0, + 0, 209, 210, 211, 212, 213, 0, 214, 215, 216, + 0, 217, 218, 219, 220, 0, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 0, 233, + 0, 234, 235, 236, 237, 0, 238, 0, 239, 0, + 0, 0, 242, 243, 540, 0, 246, 247, 248, 0, + 249, 250, 0, 252, 0, 253, 254, 255, 256, 257, + 258, 259, 0, 261, 262, 263, 264, 0, 265, 266, + 267, 268, 269, 270, 271, 0, 272, 0, 274, 275, + 276, 277, 278, 279, 280, 281, 0, 282, 0, 283, + 0, 0, 286, 0, 288, 289, 290, 0, 291, 292, + 293, 0, 0, 294, 0, 296, 0, 0, 298, 299, + 300, 301, 302, 303, 304, 305, 541, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, + 0, 331, 332, 333, 334, 335, 0, 336, 337, 0, + 339, 0, 340, 341, 342, 343, 344, 345, 0, 346, + 347, 0, 0, 348, 349, 350, 0, 0, 351, 352, + 353, 0, 355, 0, 357, 358, 359, 360, 361, 362, + 363, 0, 365, 366, 367, 368, 369, 0, 0, 0, + 0, 370, 371, 372, 0, 374, 375, 376, 377, 378, + 379, 0, 380, 381, 382, 383, 384, 385, 0, 386, + 387, 388, 0, 390, 391, 392, 393, 394, 395, 0, + 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 0, 409, 410, 0, 412, 413, 414, + 415, 0, 417, 418, 419, 420, 421, 422, 423, 424, + 425, 426, 427, 428, 0, 0, 429, 430, 431, 432, + 433, 434, 435, 436, 437, 0, 0, 439, 440, 441, + 442, 0, 443, 444, 445, 446, 447, 448, 449, 450, + 451, 452, 453, 454, 455, 456, 542, 458, 459, 0, + 0, 460, 461, 0, 462, 0, 464, 465, 466, 467, + 468, 469, 0, 470, 471, 472, 0, 0, 473, 474, + 475, 476, 477, 0, 478, 479, 480, 481, 482, 483, + 484, 485, 0, 0, 486, 487, 488, 0, 0, 489, + 490, 491, 492, 0, 493, 494, 495, 496, 497, 498, + 499, 500, 0, 501, 0, 503, 504, 505, 506, 507, + 508, 509, 0, 0, 510, 0, 0, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, + 524, 525, 526, 527, 528, 529, 530, 531, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 764, 0, + 3, 4, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 764, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, + 0, 8, 0, 0, 0, 7, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, 0, 8, + 0, 0, 0, 0, 11, 0, 765, 0, 0, 0, + 10, 0, 0, 0, 0, 0, 0, 13, 0, 0, + 0, 0, 11, 0, 765, 0, 0, 0, 0, 0, + 0, 0, 14, 15, 0, 13, 0, 0, 0, 0, + 0, 0, 0, 766, 0, 0, 0, 0, 0, 18, + 14, 15, 0, 0, 0, 0, 0, 0, 19, 0, + 0, 766, 0, 0, 0, 0, 0, 18, 0, 0, + 0, 0, 0, 0, 0, 22, 19, 0, 0, 23, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 22, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 122, 123, 124, 125, 126, 127, - 128, 129, 0, 130, 131, 132, 0, 0, 0, 3102, - 0, 0, 0, 0, 3103, 134, 135, 0, 3104, 137, - 138, 3105, 140, 141, 142, 0, 1539, 3106, 1541, 1542, - 0, 3107, 148, 149, 150, 151, 152, 0, 0, 153, - 154, 155, 156, 1544, 1545, 159, 0, 160, 161, 162, - 163, 0, 0, 3108, 0, 3109, 167, 168, 169, 170, - 171, 3110, 173, 174, 175, 0, 176, 177, 178, 179, - 180, 181, 0, 3111, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 1550, 194, 195, 1551, 197, 0, - 198, 0, 199, 200, 201, 202, 203, 204, 0, 0, - 205, 206, 207, 208, 0, 0, 209, 210, 1093, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 0, 221, 222, 223, 224, 0, 226, 227, 228, 229, - 230, 231, 0, 0, 233, 0, 234, 235, 1552, 237, - 0, 238, 0, 239, 3112, 0, 3113, 242, 243, 2472, - 3114, 246, 247, 248, 0, 0, 0, 251, 252, 0, - 253, 254, 255, 256, 257, 258, 259, 3115, 261, 262, - 263, 264, 0, 265, 266, 267, 268, 269, 270, 271, - 0, 272, 3116, 0, 275, 276, 277, 278, 279, 1558, - 1559, 0, 1560, 0, 283, 3117, 3118, 286, 3119, 288, - 289, 290, 0, 291, 292, 293, 0, 0, 294, 3120, - 296, 3121, 0, 298, 299, 300, 301, 302, 303, 304, - 305, 2481, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 1567, 3123, 1569, 332, 333, 334, - 0, 0, 336, 337, 3125, 339, 0, 0, 341, 1571, - 343, 344, 345, 0, 346, 347, 0, 0, 348, 349, - 350, 0, 0, 351, 352, 0, 3127, 355, 3128, 0, - 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, - 368, 369, 0, 0, 0, 0, 370, 371, 0, 3129, - 374, 375, 0, 377, 378, 379, 0, 380, 381, 382, - 383, 384, 385, 0, 386, 387, 388, 389, 390, 1575, - 392, 393, 394, 395, 0, 396, 397, 398, 399, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 0, 409, - 410, 3130, 412, 413, 414, 0, 416, 417, 418, 419, - 420, 421, 422, 423, 424, 425, 426, 427, 428, 0, - 3131, 429, 430, 431, 432, 433, 434, 0, 436, 437, - 0, 3133, 439, 440, 1581, 442, 0, 443, 444, 445, - 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, - 456, 2489, 458, 0, 0, 0, 460, 461, 0, 462, - 3135, 464, 465, 466, 467, 468, 469, 0, 470, 1584, - 1585, 0, 0, 473, 474, 0, 476, 0, 0, 478, - 479, 3136, 481, 482, 483, 484, 485, 0, 0, 486, - 487, 488, 3138, 0, 489, 490, 491, 492, 0, 493, - 494, 495, 496, 497, 0, 1589, 500, 0, 501, 3139, - 503, 504, 505, 506, 507, 508, 509, 0, 0, 510, - 0, 0, 511, 512, 513, 514, 515, 516, 1844, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 528, - 529, 530, 531, 0, 0, 0, 0, 0, 122, 123, - 124, 125, 126, 127, 128, 129, 0, 130, 131, 132, - 0, 0, 0, 1535, 0, 0, 0, 0, 1536, 134, - 135, 0, 1537, 137, 138, 1538, 140, 141, 142, 0, - 1539, 1540, 1541, 1542, 0, 1543, 148, 149, 150, 151, - 152, 0, 0, 153, 154, 155, 156, 1544, 1545, 159, - 0, 160, 161, 162, 163, 0, 0, 1546, 0, 1547, - 167, 168, 169, 170, 171, 1548, 173, 174, 175, 0, - 176, 177, 178, 179, 180, 181, 0, 1549, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 1550, 194, - 195, 1551, 197, 0, 198, 0, 199, 200, 201, 202, - 203, 204, 0, 0, 205, 206, 207, 208, 0, 0, - 209, 210, 1093, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 0, 221, 222, 223, 224, 0, - 226, 227, 228, 229, 230, 231, 0, 0, 233, 0, - 234, 235, 1552, 237, 0, 238, 0, 239, 1553, 0, - 1554, 242, 243, 0, 1555, 246, 247, 248, 0, 0, - 0, 251, 252, 0, 253, 254, 255, 256, 257, 258, - 259, 1556, 261, 262, 263, 264, 0, 265, 266, 267, - 268, 269, 270, 271, 0, 272, 1557, 0, 275, 276, - 277, 278, 279, 1558, 1559, 0, 1560, 0, 283, 1561, - 1562, 286, 1563, 288, 289, 290, 0, 291, 292, 293, - 0, 0, 294, 1564, 296, 1565, 0, 298, 299, 300, - 301, 302, 303, 304, 305, 0, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, 1567, 1568, - 1569, 332, 333, 334, 0, 0, 336, 337, 1570, 339, - 0, 0, 341, 1571, 343, 344, 345, 0, 346, 347, - 0, 0, 348, 349, 350, 0, 0, 351, 352, 0, - 1572, 355, 1573, 0, 358, 359, 360, 361, 362, 363, - 364, 365, 366, 367, 368, 369, 0, 0, 0, 0, - 370, 371, 0, 1574, 374, 375, 0, 377, 378, 379, - 0, 380, 381, 382, 383, 384, 385, 0, 386, 387, - 388, 389, 390, 1575, 392, 393, 394, 395, 0, 396, - 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 0, 409, 410, 1576, 412, 413, 414, 0, - 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 0, 1578, 429, 430, 431, 432, 433, - 434, 0, 436, 437, 0, 1580, 439, 440, 1581, 442, - 0, 443, 444, 445, 446, 447, 448, 449, 450, 451, - 452, 453, 454, 455, 456, 0, 458, 0, 0, 0, - 460, 461, 0, 462, 1583, 464, 465, 466, 467, 468, - 469, 0, 470, 1584, 1585, 0, 0, 473, 474, 0, - 476, 0, 0, 478, 479, 1586, 481, 482, 483, 484, - 485, 0, 0, 486, 487, 488, 1588, 0, 489, 490, - 491, 492, 0, 493, 494, 495, 496, 497, 0, 1589, - 500, 0, 501, 1590, 503, 504, 505, 506, 507, 508, - 509, 0, 0, 510, 0, 0, 511, 512, 513, 514, - 515, 516, 539, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 528, 529, 530, 531, 0, 0, 0, - 0, 0, 122, 123, 124, 125, 126, 127, 128, 129, - 0, 130, 131, 132, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 134, 135, 0, 0, 137, 138, 0, - 140, 141, 142, 143, 144, 0, 146, 147, 0, 0, - 148, 149, 150, 151, 152, 0, 0, 153, 154, 155, - 156, 157, 158, 159, 0, 160, 161, 162, 163, 164, - 0, 0, 0, 166, 167, 168, 169, 170, 171, 0, - 173, 174, 175, 0, 176, 177, 178, 179, 180, 181, - 0, 0, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 0, 198, 0, - 199, 200, 201, 202, 203, 204, 0, 0, 205, 206, - 207, 208, 0, 0, 209, 210, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 0, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 0, 233, 0, 234, 235, 236, 237, 0, 238, - 0, 239, 0, 0, 0, 242, 243, 540, 0, 246, - 247, 248, 0, 249, 250, 0, 252, 0, 253, 254, - 255, 256, 257, 258, 259, 0, 261, 262, 263, 264, - 0, 265, 266, 267, 268, 269, 270, 271, 0, 272, - 0, 274, 275, 276, 277, 278, 279, 280, 281, 0, - 282, 0, 283, 0, 0, 286, 0, 288, 289, 290, - 0, 291, 292, 293, 0, 0, 294, 0, 296, 0, - 0, 298, 299, 300, 301, 302, 303, 304, 305, 541, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 329, 0, 331, 332, 333, 334, 335, 0, - 336, 337, 0, 339, 0, 340, 341, 342, 343, 344, - 345, 0, 346, 347, 0, 0, 348, 349, 350, 0, - 0, 351, 352, 353, 0, 355, 0, 357, 358, 359, - 360, 361, 362, 363, 0, 365, 366, 367, 368, 369, - 0, 0, 0, 0, 370, 371, 372, 0, 374, 375, - 376, 377, 378, 379, 0, 380, 381, 382, 383, 384, - 385, 0, 386, 387, 388, 0, 390, 391, 392, 393, - 394, 395, 0, 396, 397, 398, 399, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 0, 409, 410, 0, - 412, 413, 414, 415, 0, 417, 418, 419, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 0, 0, 429, - 430, 431, 432, 433, 434, 435, 436, 437, 0, 0, - 439, 440, 441, 442, 0, 443, 444, 445, 446, 447, - 448, 449, 450, 451, 452, 453, 454, 455, 456, 542, - 458, 459, 0, 0, 460, 461, 0, 462, 0, 464, - 465, 466, 467, 468, 469, 0, 470, 471, 472, 0, - 0, 473, 474, 475, 476, 477, 0, 478, 479, 480, - 481, 482, 483, 484, 485, 0, 0, 486, 487, 488, - 0, 0, 489, 490, 491, 492, 0, 493, 494, 495, - 496, 497, 498, 499, 500, 0, 501, 0, 503, 504, - 505, 506, 507, 508, 509, 0, 0, 510, 0, 0, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, - 531, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 764, 0, 3, 4, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 764, - 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 0, 0, 0, 0, 0, 6, - 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, - 0, 0, 8, 0, 0, 0, 0, 11, 0, 765, - 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, - 13, 0, 0, 0, 0, 11, 0, 765, 0, 0, - 0, 0, 0, 0, 0, 14, 15, 0, 13, 0, - 0, 0, 0, 0, 0, 0, 766, 0, 0, 0, - 0, 0, 18, 14, 15, 0, 0, 0, 0, 0, - 0, 19, 0, 0, 766, 0, 0, 0, 0, 0, - 18, 0, 0, 0, 0, 0, 0, 0, 22, 19, - 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, - 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, -1524, 0, 0, 0, 0, 0, + 0, -1534, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -1534, + 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, -1524, 0, 0, 0, 0, 0, 0, 0, - 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, + 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, - 27, 28, 0, 0, 0, 0, 0, 29, 0, 0, - 30, 0, 0, 0, 0, 0, 0, 26, 27, 28, - 0, 0, 0, 0, 0, 29, 0, 0, 30, 0, + 0, 0, 0, 0, 0, 0, 26, 27, 28, 0, + 0, 0, 0, 0, 29, 0, 0, 30, 0, 0, + 0, 0, 0, 0, 26, 27, 28, 0, 0, 0, + 0, 0, 29, 0, 0, 30, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, + 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, + 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, + 0, 0, 0, 33, 0, 32, 0, 0, 0, 0, + 34, 0, 0, 0, 35, 0, 0, 0, 0, 0, + 0, 33, 0, 0, 0, 0, 36, 0, 34, 0, + 0, 0, 35, 0, 0, 0, 0, 0, 37, 0, + 0, 0, 38, 0, 36, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, + 38, 0, 0, 39, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, + 0, 39, 0, 42, 0, 0, 0, 0, 43, 0, + 0, 0, 0, 767, 0, 40, 0, 0, 0, 0, + 0, 42, 0, 0, 0, 44, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, - 32, 0, 0, 0, 0, 0, 0, 0, 0, 31, - 0, 0, 0, 0, 0, 0, 33, 0, 32, 0, - 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, - 0, 0, 0, 0, 33, 0, 0, 0, 0, 36, - 0, 34, 0, 0, 0, 35, 0, 0, 0, 0, - 0, 37, 0, 0, 0, 38, 0, 36, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, - 0, 0, 0, 38, 0, 0, 39, 0, 0, 0, + 0, 0, 0, 44, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 40, 0, 0, 0, 39, 0, 42, 0, 0, 0, - 0, 43, 0, 0, 0, 0, 767, 0, 40, 0, - 0, 0, 0, 0, 42, 0, 0, 0, 44, 43, + 0, 0, 0, 768, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, - 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 768, 0, 0, 0, - 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 46 + 0, 46 }; static const yytype_int16 yycheck[] = { - 7, 532, 0, 0, 0, 46, 880, 0, 856, 16, - 0, 0, 922, 904, 1019, 0, 23, 0, 934, 0, - 1268, 830, 20, 0, 0, 1759, 759, 1270, 1000, 38, - 1065, 985, 955, 7, 16, 20, 950, 1010, 989, 1197, - 1720, 37, 75, 1490, 1474, 1256, 1962, 79, 1636, 23, - 20, 79, 1010, 1609, 1877, 1010, 1114, 7, 1017, 13, - 2343, 1527, 1248, 1649, 1885, 19, 760, 1594, 1692, 1010, - 77, 78, 1328, 23, 1245, 1677, 30, 2267, 2277, 2833, - 1813, 17, 2082, 1233, 0, 23, 2246, 0, 2248, 0, - 44, 45, 1673, 1674, 2830, 2789, 45, 2212, 2789, 1828, - 0, 2266, 1273, 77, 78, 114, 0, 103, 2850, 0, - 34, 1377, 1028, 2334, 0, 767, 1162, 0, 1123, 2857, - 2417, 1167, 2653, 825, 2497, 1724, 0, 77, 78, 831, - 0, 1899, 0, 768, 1008, 0, 0, 1866, 0, 77, - 78, 1898, 0, 1902, 2055, 2056, 0, 2740, 1872, 0, - 23, 2744, 2045, 2046, 2047, 2066, 1087, 1088, 112, 2070, - 0, 9, 9, 2969, 922, 0, 924, 2430, 926, 41, - 0, 0, 5, 1692, 1105, 0, 0, 0, 2017, 5, - 56, 3, 0, 5, 5, 0, 5, 64, 10, 60, - 4, 81, 13, 14, 5, 9, 10, 2425, 9, 5, - 5, 1173, 1011, 5, 77, 78, 5, 13, 14, 5, - 5, 13, 14, 2430, 0, 19, 2437, 1819, 13, 14, - 3197, 5, 13, 14, 2392, 1777, 5, 19, 83, 1779, - 5, 5, 5, 5, 13, 14, 9, 5, 793, 5, - 2423, 31, 5, 5, 83, 2832, 125, 118, 1122, 39, - 19, 27, 13, 14, 109, 94, 4, 1292, 3, 4, - 5, 9, 140, 1179, 9, 11, 928, 175, 1303, 46, - 16, 11, 193, 83, 201, 46, 16, 120, 174, 899, - 77, 78, 19, 149, 94, 1257, 101, 3076, 1260, 1261, - 91, 822, 174, 1207, 4, 3, 31, 3148, 174, 9, - 899, 47, 2523, 2524, 39, 2526, 60, 295, 1091, 64, - 1012, 180, 229, 1034, 108, 101, 183, 2597, 1039, 3178, - 1041, 176, 1024, 1925, 31, 1108, 3029, 35, 36, 130, - 296, 1489, 39, 301, 875, 81, 3181, 296, 869, 1060, - 293, 5, 820, 374, 11, 195, 319, 3384, 15, 16, - 205, 1003, 388, 301, 220, 186, 3201, 41, 1232, 5, - 3560, 278, 138, 281, 123, 1000, 65, 108, 1579, 1527, - 316, 107, 2699, 118, 2701, 244, 75, 1979, 108, 168, - 1228, 1229, 133, 41, 31, 3309, 118, 3311, 351, 1991, - 121, 2757, 120, 42, 249, 195, 84, 118, 3529, 123, - 164, 31, 375, 284, 75, 490, 121, 3639, 1102, 11, - 134, 492, 2235, 15, 16, 2575, 166, 439, 3481, 2021, - 3483, 426, 146, 11, 467, 417, 2028, 390, 3593, 514, - 347, 150, 11, 514, 809, 301, 15, 16, 3192, 13, - 14, 3132, 1333, 295, 253, 47, 123, 3741, 4, 1363, - 123, 11, 827, 9, 3208, 15, 16, 479, 3194, 47, - 406, 466, 150, 11, 427, 173, 197, 175, 47, 1392, - 2072, 280, 193, 2756, 2076, 166, 221, 241, 127, 81, - 295, 398, 197, 202, 234, 528, 133, 133, 64, 366, - 482, 215, 3692, 81, 178, 3626, 532, 528, 3629, 244, - 171, 3564, 81, 133, 2106, 3737, 3800, 1466, 1467, 295, - 379, 2877, 313, 1472, 364, 346, 162, 480, 3442, 255, - 178, 402, 27, 299, 379, 2640, 3691, 1585, 33, 2728, - 266, 3382, 2753, 81, 2755, 390, 495, 278, 215, 290, - 528, 330, 215, 76, 375, 244, 464, 464, 174, 3408, - 523, 3528, 367, 285, 550, 3344, 2083, 285, 440, 280, - 1038, 361, 528, 432, 532, 434, 4, 3004, 3413, 3006, - 109, 9, 427, 2159, 3363, 528, 2397, 2398, 2399, 256, - 2907, 367, 528, 479, 532, 379, 277, 363, 467, 365, - 456, 460, 414, 415, 2218, 169, 451, 64, 605, 1130, - 467, 440, 473, 2866, 3735, 532, 1480, 528, 486, 2075, - 1230, 366, 566, 1544, 1545, 405, 2844, 3204, 1280, 395, - 528, 285, 3325, 605, 2212, 480, 469, 3330, 1884, 3666, - 440, 1230, 433, 138, 280, 1190, 526, 2805, 1569, 285, - 530, 395, 25, 1376, 290, 2925, 1494, 424, 1381, 2866, - 3627, 477, 528, 424, 1387, 532, 2839, 528, 530, 3465, - 3402, 109, 1203, 2884, 335, 1206, 2434, 2391, 1516, 2250, - 405, 2270, 519, 520, 2431, 490, 1919, 531, 2678, 527, - 2439, 1947, 2593, 2576, 2577, 2578, 2579, 1722, 2276, 1383, - 3384, 531, 532, 3384, 2533, 528, 492, 427, 405, 2218, - 1631, 1632, 528, 536, 490, 464, 528, 528, 492, 528, - 528, 533, 534, 531, 529, 536, 531, 528, 514, 533, - 534, 526, 528, 528, 3097, 530, 528, 768, 532, 528, - 514, 2283, 528, 528, 2284, 527, 119, 528, 1612, 1613, - 464, 1393, 3335, 529, 528, 531, 3277, 3340, 1622, 528, - 1666, 1667, 1668, 528, 528, 528, 528, 3054, 527, 1394, - 528, 768, 528, 1637, 3047, 528, 528, 528, 1551, 767, - 478, 519, 520, 3527, 519, 520, 175, 532, 524, 820, - 490, 1502, 767, 3628, 524, 1487, 457, 464, 1571, 526, - 366, 464, 3534, 530, 299, 1669, 3233, 3535, 768, 1987, - 27, 447, 809, 1524, 514, 2716, 33, 761, 467, 519, - 520, 278, 458, 820, 440, 151, 280, 109, 827, 8, - 827, 285, 11, 1606, 2080, 528, 15, 16, 271, 442, - 2018, 20, 21, 22, 517, 809, 397, 254, 365, 2441, - 872, 407, 492, 432, 872, 434, 820, 530, 34, 856, - 857, 3586, 3587, 827, 521, 522, 523, 524, 363, 809, - 123, 229, 3027, 280, 514, 431, 875, 203, 395, 528, - 820, 904, 2030, 880, 60, 138, 1848, 827, 528, 2700, - 493, 345, 820, 3637, 327, 894, 1858, 3623, 0, 1861, - 395, 517, 890, 890, 890, 2497, 109, 890, 2898, 366, - 890, 890, 194, 936, 530, 890, 3641, 890, 878, 890, - 278, 138, 517, 890, 890, 314, 205, 2075, 3033, 521, - 522, 523, 524, 528, 523, 932, 933, 881, 395, 936, - 937, 530, 881, 1843, 858, 859, 809, 861, 83, 863, - 519, 520, 521, 522, 523, 524, 133, 820, 3684, 94, - 164, 432, 427, 434, 827, 169, 1689, 38, 3179, 519, - 520, 521, 522, 523, 524, 470, 4, 528, 2415, 83, - 2236, 9, 3666, 2597, 890, 3666, 531, 890, 1929, 890, - 94, 532, 989, 2983, 1907, 2808, 2809, 1878, 1879, 1880, - 890, 1945, 205, 1000, 2040, 1949, 890, 1038, 1952, 890, - 1007, 1008, 401, 1954, 890, 1003, 1013, 890, 300, 1016, - 1017, 2613, 1019, 1020, 1021, 1022, 890, 3771, 1003, 955, - 890, 2754, 890, 820, 478, 890, 890, 241, 890, 1036, - 398, 1038, 890, 1992, 1993, 1994, 1995, 1996, 1997, 890, - 1047, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2780, 2640, 1811, 216, 890, 105, 1064, 1065, 1066, - 890, 890, 1036, 3346, 1038, 890, 890, 890, 361, 41, - 2799, 334, 299, 1047, 2340, 3752, 75, 164, 292, 1086, - 72, 73, 1123, 3760, 2665, 1843, 1036, 164, 1038, 61, - 379, 526, 169, 280, 175, 530, 464, 1047, 1036, 1106, - 1038, 390, 2252, 290, 2254, 1863, 3081, 280, 297, 1047, - 1868, 1118, 1119, 1120, 3089, 1122, 1123, 27, 1125, 118, - 5, 1854, 351, 33, 1655, 2555, 1859, 2574, 2371, 174, - 211, 3321, 359, 54, 183, 107, 363, 492, 427, 176, - 1613, 13, 14, 1125, 120, 248, 227, 2403, 2306, 1622, - 27, 1158, 2026, 523, 241, 529, 33, 238, 532, 514, - 530, 390, 528, 1036, 241, 1038, 379, 180, 395, 1176, - 1177, 1970, 2995, 528, 1047, 1974, 38, 390, 1977, 1211, - 1212, 526, 1214, 1211, 1212, 530, 1214, 2789, 347, 133, - 1043, 480, 205, 528, 1203, 526, 1049, 1206, 427, 530, - 109, 2789, 264, 265, 529, 292, 1213, 532, 2379, 31, - 1217, 1218, 249, 316, 427, 292, 13, 14, 162, 3502, - 1227, 1228, 1229, 529, 180, 1232, 532, 3227, 138, 278, - 2832, 244, 204, 209, 2193, 2194, 526, 2242, 528, 1036, - 530, 1038, 1196, 470, 2118, 1479, 361, 1481, 1482, 1256, - 1047, 480, 858, 859, 205, 861, 529, 863, 179, 532, - 3176, 138, 2448, 1272, 86, 1048, 386, 480, 529, 1052, - 257, 532, 2458, 95, 445, 196, 321, 322, 323, 529, - 201, 280, 532, 255, 386, 1292, 285, 300, 244, 370, - 843, 844, 845, 427, 266, 848, 1303, 119, 526, 480, - 528, 2925, 278, 406, 280, 383, 278, 529, 389, 529, - 532, 386, 532, 175, 351, 3048, 490, 529, 492, 240, - 532, 1328, 384, 385, 2198, 6, 515, 516, 517, 10, - 519, 520, 521, 522, 523, 524, 335, 18, 310, 529, - 528, 285, 532, 388, 529, 529, 290, 532, 532, 211, - 3171, 32, 528, 390, 353, 36, 2247, 460, 169, 529, - 529, 1368, 532, 532, 528, 227, 379, 1350, 528, 1350, - 1377, 193, 528, 1350, 1350, 2961, 238, 529, 176, 2826, - 532, 432, 427, 434, 206, 528, 1368, 1394, 437, 299, - 427, 528, 2346, 365, 2348, 1393, 529, 529, 529, 532, - 532, 532, 529, 529, 1411, 532, 532, 2934, 1393, 1416, - 2937, 5, 2939, 529, 451, 174, 532, 462, 390, 432, - 803, 434, 299, 529, 1394, 528, 532, 528, 473, 1411, - 1384, 529, 1386, 529, 532, 2901, 532, 2595, 432, 411, - 434, 2599, 528, 480, 457, 3033, 149, 460, 2349, 359, - 2351, 249, 835, 363, 2753, 528, 2755, 3013, 457, 1466, - 1467, 164, 896, 2311, 898, 1472, 169, 1474, 467, 528, - 2164, 521, 1479, 1480, 1481, 1482, 432, 860, 434, 400, - 3763, 529, 359, 528, 532, 395, 363, 1494, 1495, 529, - 529, 19, 532, 532, 514, 3097, 528, 1504, 529, 1506, - 1474, 532, 1509, 447, 460, 13, 14, 1514, 370, 1516, - 1517, 511, 1519, 226, 458, 2429, 1523, 220, 395, 529, - 13, 14, 532, 2771, 1474, 529, 909, 389, 532, 2772, - 1504, 295, 1506, 127, 128, 1509, 3696, 530, 241, 3738, - 1514, 3740, 511, 1517, 529, 1519, 532, 532, 173, 1523, - 248, 3711, 529, 351, 1504, 532, 1506, 529, 529, 1509, - 470, 532, 529, 528, 1514, 532, 1504, 1517, 1506, 1519, - 529, 1509, 1579, 1523, 529, 2823, 1514, 532, 174, 1517, - 174, 1519, 13, 14, 2770, 1523, 2772, 2645, 2646, 292, - 529, 413, 390, 470, 416, 529, 3198, 60, 301, 300, - 3799, 1474, 3204, 222, 529, 1612, 1613, 532, 3524, 13, - 14, 1609, 1609, 1609, 1621, 1622, 1609, 1000, 316, 1609, - 1609, 13, 14, 1630, 1609, 3785, 528, 1010, 428, 427, - 1637, 1504, 529, 1506, 174, 532, 1509, 1644, 3798, 529, - 511, 1514, 532, 226, 1517, 154, 1519, 2620, 2653, 0, - 1523, 3474, 3475, 451, 13, 14, 154, 1664, 1665, 13, - 14, 109, 1669, 2621, 2622, 1672, 2621, 2622, 2623, 3271, + 7, 0, 532, 922, 1065, 759, 880, 856, 0, 16, + 46, 0, 950, 0, 904, 830, 23, 0, 934, 1270, + 16, 38, 0, 0, 0, 0, 1256, 1268, 20, 0, + 0, 1019, 1579, 20, 1490, 75, 1000, 1720, 37, 1010, + 955, 1636, 1010, 1197, 1474, 1962, 1114, 79, 760, 1759, + 2279, 1248, 7, 1527, 1594, 989, 1649, 985, 1677, 20, + 79, 1813, 1877, 1885, 1692, 1609, 1010, 2082, 23, 2269, + 77, 78, 2248, 1233, 2250, 1245, 1673, 1674, 1328, 1828, + 17, 1377, 2345, 0, 2214, 2336, 77, 78, 0, 0, + 0, 7, 45, 0, 0, 0, 0, 114, 2862, 768, + 2834, 0, 1010, 1273, 103, 2268, 2854, 23, 2420, 0, + 2055, 2056, 1028, 2837, 922, 2498, 924, 1866, 926, 767, + 34, 2066, 77, 78, 2656, 2070, 2743, 1899, 1724, 0, + 2747, 825, 0, 0, 1008, 1123, 0, 831, 0, 1902, + 0, 1898, 0, 0, 0, 2017, 1000, 0, 0, 1162, + 0, 0, 0, 0, 1167, 1087, 1088, 0, 1872, 1692, + 23, 77, 78, 2045, 2046, 2047, 1777, 40, 5, 41, + 40, 5, 3156, 1105, 0, 2976, 3, 2433, 5, 13, + 14, 4, 56, 10, 64, 5, 9, 10, 2433, 2440, + 5, 5, 5, 5, 5, 5, 1011, 1779, 13, 14, + 1819, 5, 13, 14, 5, 9, 5, 5, 5, 1173, + 9, 5, 13, 14, 77, 78, 13, 14, 9, 2428, + 5, 75, 11, 2426, 5, 928, 19, 16, 23, 2395, + 5, 1292, 5, 5, 5, 5, 175, 27, 46, 13, + 14, 120, 1303, 46, 793, 13, 14, 3348, 1122, 3, + 4, 5, 4, 875, 19, 9, 19, 9, 101, 193, + 3140, 9, 31, 1179, 3348, 201, 174, 108, 19, 1207, + 39, 140, 11, 2524, 2525, 101, 2527, 16, 174, 109, + 3380, 125, 77, 78, 4, 229, 3166, 83, 1142, 9, + 123, 1017, 822, 1257, 5, 31, 1260, 1261, 94, 1091, + 174, 134, 64, 39, 3137, 3036, 1925, 123, 47, 64, + 60, 899, 3, 146, 91, 3083, 1108, 171, 1012, 1173, + 2836, 133, 295, 11, 293, 319, 118, 15, 16, 174, + 1024, 1000, 296, 11, 278, 1489, 301, 15, 16, 869, + 3541, 2598, 81, 60, 35, 36, 175, 81, 138, 1579, + 162, 108, 83, 130, 296, 1003, 316, 11, 1232, 47, + 1979, 15, 16, 94, 118, 3011, 109, 3013, 118, 1034, + 316, 195, 1991, 1527, 1039, 205, 1041, 133, 123, 1228, + 1229, 375, 215, 301, 65, 123, 118, 281, 168, 820, + 1102, 13, 14, 81, 75, 1060, 41, 3576, 388, 215, + 2576, 108, 2021, 1257, 2760, 166, 1260, 1261, 31, 2028, + 3609, 120, 3659, 321, 322, 323, 39, 164, 2702, 3153, + 2704, 123, 2237, 31, 121, 1363, 31, 3151, 11, 11, + 3514, 3766, 15, 16, 121, 150, 138, 84, 42, 271, + 256, 3642, 11, 1333, 54, 467, 406, 467, 3649, 3173, + 899, 194, 295, 2072, 398, 490, 809, 2076, 517, 151, + 406, 193, 174, 166, 47, 47, 1613, 221, 280, 295, + 215, 530, 517, 285, 827, 1622, 442, 1392, 290, 514, + 388, 335, 173, 528, 175, 314, 366, 202, 365, 2108, + 244, 3826, 1218, 285, 241, 327, 2759, 3377, 81, 81, + 197, 1227, 2731, 150, 76, 2756, 528, 2758, 528, 299, + 197, 203, 81, 2643, 3713, 3762, 277, 1585, 395, 427, + 464, 109, 183, 127, 367, 133, 2882, 493, 133, 523, + 490, 234, 492, 178, 290, 3714, 313, 3637, 379, 3372, + 364, 367, 532, 3311, 2084, 1399, 1400, 169, 280, 379, + 330, 550, 3198, 495, 462, 528, 3540, 300, 3759, 528, + 390, 3292, 3330, 244, 528, 473, 3297, 532, 2161, 179, + 464, 278, 401, 363, 285, 365, 285, 1280, 2400, 2401, + 2402, 1203, 528, 479, 1206, 3686, 196, 414, 415, 528, + 469, 201, 2220, 13, 528, 440, 532, 427, 605, 19, + 1130, 2075, 3686, 457, 366, 395, 1480, 1038, 3708, 605, + 30, 366, 1544, 1545, 532, 2871, 424, 486, 3366, 2214, + 528, 424, 1376, 467, 44, 45, 2871, 1381, 2912, 3430, + 240, 464, 334, 1387, 1884, 447, 405, 1569, 2889, 2848, + 2843, 1190, 1230, 2809, 440, 1494, 458, 490, 464, 2594, + 480, 1947, 532, 3169, 528, 2252, 433, 530, 530, 3643, + 530, 1722, 2534, 477, 490, 2437, 2681, 1516, 1919, 405, + 427, 1383, 528, 2930, 2285, 531, 2272, 2434, 395, 2442, + 2394, 531, 532, 2278, 531, 3302, 529, 2220, 531, 526, + 3307, 528, 112, 530, 528, 2577, 2578, 2579, 2580, 1631, + 1632, 528, 536, 529, 2286, 531, 533, 534, 528, 440, + 533, 534, 3244, 528, 528, 528, 536, 528, 528, 464, + 492, 3104, 492, 473, 528, 1394, 464, 528, 440, 528, + 528, 528, 768, 526, 528, 524, 527, 530, 1612, 1613, + 1466, 1467, 514, 528, 514, 1393, 1472, 528, 1622, 3061, + 1666, 1667, 1668, 528, 528, 528, 528, 528, 528, 1551, + 528, 768, 527, 1637, 3644, 519, 520, 519, 520, 532, + 490, 519, 520, 1627, 2719, 767, 527, 532, 528, 1571, + 767, 1230, 405, 3547, 820, 524, 1640, 478, 1642, 107, + 400, 3054, 526, 1487, 514, 1669, 530, 27, 3546, 519, + 520, 195, 809, 33, 105, 517, 467, 768, 164, 133, + 827, 120, 397, 820, 1606, 3539, 41, 1671, 530, 295, + 827, 3276, 64, 3278, 417, 2444, 3446, 374, 3448, 820, + 2080, 519, 520, 521, 522, 523, 524, 1502, 439, 492, + 872, 519, 520, 521, 522, 523, 524, 3602, 3603, 856, + 857, 83, 3530, 872, 809, 426, 149, 529, 875, 1524, + 532, 514, 94, 253, 904, 820, 3777, 521, 522, 523, + 524, 3034, 827, 880, 3785, 528, 2030, 894, 479, 2498, + 492, 2703, 183, 186, 1848, 241, 180, 3138, 2903, 482, + 280, 890, 176, 809, 1858, 466, 936, 1861, 890, 109, + 209, 890, 514, 890, 820, 3639, 3661, 890, 138, 427, + 3040, 827, 890, 890, 890, 890, 528, 878, 531, 890, + 890, 2075, 1776, 1777, 1843, 932, 933, 220, 881, 936, + 937, 284, 528, 3657, 133, 1689, 292, 255, 521, 522, + 523, 524, 2238, 528, 858, 859, 809, 861, 266, 863, + 244, 3406, 27, 178, 3632, 27, 280, 820, 33, 0, + 3580, 33, 2418, 162, 827, 249, 290, 361, 1043, 278, + 2598, 280, 3706, 890, 1049, 2990, 83, 278, 890, 890, + 890, 528, 989, 890, 890, 890, 890, 94, 1878, 1879, + 1880, 890, 1907, 1000, 1848, 1929, 2615, 2812, 2813, 890, + 1007, 1008, 1038, 1811, 1858, 2757, 1013, 1861, 301, 1016, + 1017, 1003, 1019, 1020, 1021, 1022, 1003, 1945, 955, 890, + 1954, 1949, 890, 890, 1952, 820, 890, 2040, 890, 1036, + 890, 1038, 890, 890, 2783, 1843, 278, 890, 890, 1765, + 1047, 890, 890, 346, 176, 1036, 2342, 1038, 2643, 402, + 3313, 133, 254, 492, 2803, 1863, 1047, 1064, 1065, 1066, + 1868, 532, 1987, 138, 180, 351, 138, 351, 205, 299, + 180, 2668, 375, 3797, 407, 514, 34, 280, 280, 1086, + 162, 1036, 285, 1038, 280, 379, 285, 1123, 3288, 248, + 523, 290, 1047, 2018, 2254, 205, 2256, 530, 431, 1106, + 1854, 60, 60, 4, 390, 1859, 390, 478, 9, 264, + 265, 1118, 1119, 1120, 180, 1122, 1123, 249, 1125, 2575, + 1036, 216, 1038, 2374, 366, 1655, 2556, 3088, 244, 1125, + 361, 1047, 164, 363, 244, 3096, 437, 169, 432, 205, + 434, 427, 345, 427, 858, 859, 566, 861, 523, 863, + 5, 1158, 2026, 395, 2308, 530, 2406, 316, 191, 192, + 38, 72, 73, 456, 526, 395, 460, 451, 530, 1176, + 1177, 41, 180, 1036, 432, 1038, 434, 3192, 244, 1211, + 1212, 1970, 1214, 347, 1047, 1974, 1203, 3002, 1977, 1206, + 300, 61, 1211, 1212, 480, 1214, 480, 526, 280, 27, + 528, 530, 75, 285, 3467, 33, 1213, 528, 290, 241, + 1217, 1218, 2382, 529, 109, 174, 532, 2836, 3135, 351, + 1227, 1228, 1229, 529, 299, 1232, 532, 299, 164, 384, + 385, 264, 265, 169, 300, 361, 244, 107, 2092, 4, + 470, 1036, 379, 1038, 9, 118, 2120, 406, 447, 1256, + 526, 386, 1047, 390, 530, 1272, 2244, 386, 390, 458, + 292, 1479, 2459, 1481, 1482, 229, 1992, 1993, 1994, 1995, + 1996, 1997, 13, 14, 2000, 2001, 2002, 2003, 2004, 2005, + 2006, 2007, 2008, 2009, 359, 1292, 8, 359, 363, 11, + 427, 363, 205, 15, 16, 427, 1303, 175, 20, 21, + 22, 460, 2930, 3055, 4, 241, 351, 1048, 3130, 9, + 138, 1052, 320, 379, 278, 432, 432, 434, 434, 451, + 395, 1328, 432, 395, 434, 526, 2200, 528, 526, 530, + 528, 257, 248, 211, 204, 843, 844, 845, 427, 529, + 848, 761, 532, 480, 460, 390, 445, 457, 480, 227, + 460, 384, 385, 13, 14, 529, 292, 25, 532, 2249, + 238, 1368, 321, 322, 323, 447, 432, 1350, 434, 528, + 1377, 379, 1368, 1350, 2830, 2968, 458, 480, 386, 1350, + 1350, 529, 427, 347, 532, 255, 529, 1394, 383, 532, + 1017, 457, 13, 14, 460, 470, 266, 2251, 470, 2939, + 316, 1393, 386, 2943, 1411, 2945, 1393, 280, 278, 1416, + 529, 529, 285, 532, 532, 1411, 13, 14, 529, 27, + 2348, 532, 2350, 528, 432, 33, 434, 13, 14, 388, + 2284, 2285, 2906, 1394, 398, 480, 529, 169, 529, 532, + 310, 532, 2596, 174, 529, 3040, 2600, 532, 528, 27, + 529, 119, 460, 532, 2166, 33, 2351, 528, 2353, 1466, + 1467, 881, 335, 379, 2313, 1472, 528, 1474, 427, 2195, + 2196, 299, 1479, 1480, 1481, 1482, 3020, 19, 529, 529, + 353, 532, 532, 529, 528, 3104, 532, 1494, 1495, 432, + 406, 434, 370, 529, 2432, 365, 532, 1504, 529, 1506, + 464, 532, 1509, 462, 432, 529, 434, 1514, 532, 1516, + 1517, 389, 1519, 1504, 473, 1506, 1523, 528, 1509, 1474, + 390, 13, 14, 1514, 2775, 3788, 1517, 2756, 1519, 2758, + 138, 359, 1523, 2774, 3763, 363, 3765, 529, 3157, 27, + 532, 411, 3718, 529, 460, 33, 532, 13, 14, 1504, + 3169, 1506, 529, 529, 1509, 532, 532, 3733, 1474, 1514, + 138, 6, 1517, 529, 1519, 10, 532, 395, 1523, 528, + 13, 14, 1579, 18, 528, 297, 2773, 248, 2775, 529, + 2648, 2649, 532, 528, 457, 2311, 2827, 32, 1504, 529, + 1506, 36, 532, 1509, 467, 528, 3825, 529, 1514, 529, + 532, 1517, 532, 1519, 528, 1612, 1613, 1523, 13, 14, + 1609, 1474, 528, 528, 1621, 1622, 521, 1609, 3237, 3536, + 1609, 528, 1609, 1630, 3439, 3440, 248, 13, 14, 529, + 1637, 1609, 532, 1609, 1609, 3811, 529, 1644, 514, 532, + 511, 1504, 470, 1506, 529, 316, 1509, 532, 3824, 529, + 138, 1514, 532, 2624, 1517, 2623, 1519, 1664, 1665, 529, + 1523, 2858, 1669, 529, 529, 1672, 532, 532, 2656, 226, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, - 2621, 379, 480, 1690, 1691, 1692, 13, 14, 1695, 1722, - 359, 180, 1699, 13, 14, 1702, 1703, 1704, 1705, 1706, - 1707, 1708, 1709, 1710, 1686, 359, 1713, 1504, 406, 1506, - 13, 14, 1509, 1720, 154, 1722, 205, 1514, 1692, 154, - 1517, 154, 1519, 2682, 2683, 248, 1523, 321, 322, 323, - 1762, 13, 14, 1740, 1762, 191, 192, 13, 14, 13, - 14, 13, 14, 13, 14, 13, 14, 374, 375, 1132, - 101, 248, 154, 456, 41, 244, 13, 14, 1765, 1142, - 427, 27, 460, 13, 14, 528, 8, 33, 1738, 1776, - 1777, 374, 375, 15, 16, 529, 2509, 280, 20, 21, - 22, 1164, 3384, 13, 14, 13, 14, 13, 14, 480, - 1173, 27, 90, 316, 388, 494, 3384, 33, 149, 13, - 14, 13, 14, 2719, 154, 399, 3486, 154, 264, 265, - 133, 300, 1819, 164, 13, 14, 374, 375, 169, 316, - 374, 375, 1829, 174, 268, 269, 1833, 384, 385, 423, - 528, 295, 183, 427, 13, 14, 530, 188, 154, 162, - 154, 8, 472, 473, 11, 3717, 3718, 1829, 15, 16, - 361, 1833, 3095, 20, 21, 22, 379, 2499, 2500, 440, - 1814, 3706, 3707, 3747, 3748, 1176, 1177, 1874, 462, 220, - 1877, 1825, 138, 1827, 2318, 2319, 1830, 1884, 528, 473, - 1887, 1888, 379, 406, 528, 528, 1840, 529, 1842, 180, - 241, 528, 1874, 429, 2742, 47, 490, 222, 1281, 227, - 305, 1855, 138, 60, 528, 227, 1860, 528, 227, 406, - 1864, 1865, 302, 1867, 2837, 1869, 1870, 2868, 1925, 2793, - 514, 3132, 1929, 2814, 41, 5, 2880, 1923, 384, 385, - 239, 528, 5, 27, 528, 528, 2895, 460, 331, 33, - 1947, 292, 528, 432, 295, 434, 528, 1954, 1955, 2863, - 301, 528, 5, 244, 5, 528, 1963, 280, 5, 528, - 3694, 2996, 285, 460, 3698, 5, 528, 290, 457, 528, - 9, 460, 1979, 248, 491, 528, 1983, 1984, 307, 1986, - 532, 105, 532, 529, 1991, 1992, 1993, 1994, 1995, 1996, - 1997, 342, 467, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 222, 3434, 528, 395, 169, 2015, 2016, - 169, 292, 2019, 290, 2021, 60, 367, 174, 239, 2026, - 440, 2028, 528, 440, 94, 532, 440, 1410, 60, 320, - 60, 528, 440, 299, 201, 19, 271, 440, 3772, 224, - 248, 316, 528, 2050, 138, 440, 8, 490, 386, 11, - 2057, 154, 2059, 15, 16, 297, 2063, 224, 20, 21, - 22, 440, 280, 299, 3666, 2072, 149, 101, 201, 2076, - 280, 2078, 41, 2080, 99, 2082, 427, 280, 3666, 528, - 280, 164, 41, 2057, 280, 280, 169, 528, 379, 2063, - 154, 530, 174, 359, 13, 386, 174, 363, 532, 2106, - 529, 529, 127, 128, 379, 456, 529, 2057, 316, 528, - 3069, 2118, 2119, 2063, 3086, 487, 467, 529, 2125, 2057, - 529, 1000, 529, 359, 447, 2063, 227, 363, 529, 395, - 297, 406, 529, 287, 528, 458, 487, 220, 489, 490, - 227, 432, 1066, 434, 3098, 3099, 287, 528, 528, 174, - 3398, 2158, 528, 530, 532, 2162, 477, 2198, 241, 395, - 2167, 2168, 528, 3593, 321, 322, 323, 528, 528, 460, - 528, 379, 40, 530, 486, 526, 528, 9, 529, 530, - 531, 11, 438, 248, 2057, 460, 2193, 2194, 528, 438, - 2063, 2198, 361, 527, 19, 532, 532, 2930, 406, 438, - 3647, 285, 537, 440, 470, 299, 183, 2214, 3638, 292, - 2217, 2218, 2219, 528, 165, 532, 174, 229, 301, 529, - 41, 467, 467, 220, 532, 271, 398, 229, 2235, 2236, - 296, 388, 532, 319, 470, 2242, 0, 3242, 2245, 201, - 319, 183, 38, 532, 2218, 529, 222, 43, 359, 1173, - 528, 316, 460, 528, 2261, 229, 280, 229, 2265, 530, - 2057, 3691, 224, 1142, 301, 359, 2063, 3226, 2275, 363, - 427, 2245, 60, 515, 516, 517, 60, 519, 520, 521, - 522, 523, 524, 287, 60, 2292, 2293, 2261, 60, 287, - 340, 2265, 293, 480, 1173, 2245, 321, 322, 323, 3457, - 529, 395, 2309, 2257, 2311, 462, 102, 2245, 154, 3, - 154, 2261, 528, 528, 379, 2265, 473, 154, 154, 2326, - 528, 154, 490, 2261, 41, 154, 532, 2265, 532, 295, - 280, 3, 1256, 2340, 3067, 297, 41, 101, 295, 60, - 174, 406, 2349, 2350, 2351, 11, 41, 1730, 515, 516, - 517, 169, 519, 520, 521, 522, 523, 524, 529, 529, - 183, 169, 528, 388, 529, 529, 3, 2349, 2350, 2351, - 528, 528, 2245, 456, 399, 528, 470, 40, 1257, 175, - 3, 1260, 1261, 526, 118, 149, 526, 2394, 2261, 527, - 529, 149, 2265, 529, 529, 460, 2403, 174, 423, 440, - 164, 532, 427, 537, 440, 169, 164, 440, 530, 440, - 174, 169, 511, 529, 529, 211, 511, 529, 359, 183, - 529, 1804, 1805, 448, 188, 8, 3669, 150, 11, 2436, - 530, 227, 15, 16, 2441, 511, 529, 462, 529, 2422, - 174, 2422, 238, 526, 174, 2422, 2422, 530, 473, 440, - 3364, 528, 487, 528, 2436, 157, 220, 528, 60, 528, - 528, 41, 220, 528, 47, 490, 247, 60, 2265, 532, - 513, 54, 296, 517, 296, 464, 532, 241, 274, 60, - 271, 75, 280, 241, 479, 440, 440, 81, 1871, 514, - 2497, 205, 154, 154, 2501, 154, 440, 2451, 81, 295, - 94, 528, 528, 528, 440, 528, 1889, 1890, 440, 3040, - 2517, 440, 529, 528, 528, 41, 41, 295, 361, 529, - 1399, 1400, 293, 532, 118, 321, 120, 490, 292, 528, - 41, 295, 328, 38, 292, 2517, 528, 301, 43, 154, - 285, 529, 174, 301, 321, 322, 323, 528, 2555, 528, - 60, 529, 188, 515, 516, 517, 529, 519, 520, 521, - 522, 523, 524, 14, 1066, 529, 169, 81, 529, 3443, - 526, 3445, 3488, 144, 370, 309, 529, 529, 342, 174, - 528, 2555, 529, 532, 529, 19, 1969, 321, 322, 323, - 2597, 529, 532, 389, 528, 306, 179, 102, 529, 254, - 528, 367, 528, 367, 296, 2555, 2613, 3455, 529, 183, - 154, 388, 2653, 196, 532, 209, 2625, 529, 201, 528, - 178, 529, 529, 2630, 451, 529, 528, 530, 528, 528, - 2637, 2638, 41, 87, 41, 41, 41, 532, 174, 467, - 528, 489, 529, 529, 201, 529, 2653, 2688, 3653, 3458, - 427, 3460, 527, 527, 388, 1579, 532, 240, 529, 2666, - 2693, 473, 2669, 427, 2671, 529, 462, 529, 529, 532, - 175, 2678, 2679, 295, 60, 2682, 2683, 486, 517, 529, - 2687, 2688, 2555, 490, 3598, 462, 280, 2694, 529, 529, - 207, 285, 456, 427, 3585, 118, 473, 3607, 456, 41, - 229, 2742, 528, 467, 2711, 89, 211, 194, 285, 529, - 285, 530, 517, 490, 297, 2722, 530, 530, 529, 2715, - 530, 440, 227, 487, 530, 489, 490, 530, 462, 530, - 3578, 530, 440, 238, 527, 2742, 530, 514, 530, 473, - 530, 335, 41, 530, 530, 530, 280, 530, 1627, 528, - 530, 528, 108, 1677, 1256, 530, 490, 530, 527, 353, - 530, 1640, 526, 1642, 529, 529, 530, 531, 526, 274, - 530, 529, 530, 530, 530, 530, 530, 530, 530, 2786, - 514, 530, 2789, 2790, 530, 2792, 2793, 2794, 530, 530, - 530, 2745, 1671, 530, 528, 2749, 532, 530, 530, 490, - 529, 2808, 2809, 529, 2786, 529, 528, 427, 2790, 295, - 2792, 41, 528, 9, 2821, 360, 321, 400, 528, 528, - 2861, 342, 529, 328, 2778, 2832, 532, 60, 532, 529, - 201, 61, 529, 2840, 2875, 2831, 532, 527, 472, 194, - 529, 2795, 2796, 2797, 2798, 532, 2800, 2801, 2802, 2803, - 2804, 92, 529, 2836, 353, 2836, 7, 8, 528, 2836, - 2836, 2868, 13, 457, 41, 370, 154, 125, 19, 2865, - 530, 529, 23, 467, 25, 154, 41, 107, 29, 30, - 31, 2922, 529, 34, 389, 375, 37, 38, 2895, 41, - 41, 2898, 375, 44, 45, 1819, 529, 1776, 1777, 528, - 528, 41, 3635, 467, 528, 532, 37, 315, 2915, 2916, - 253, 2918, 528, 285, 252, 2922, 193, 467, 2925, 451, - 528, 75, 298, 81, 9, 75, 77, 78, 529, 512, - 529, 528, 377, 3807, 60, 527, 519, 520, 521, 522, - 523, 524, 529, 527, 134, 2952, 94, 436, 178, 60, - 517, 278, 103, 451, 295, 41, 528, 462, 298, 110, - 111, 112, 113, 114, 115, 2972, 298, 528, 472, 1848, - 2977, 2978, 207, 2356, 204, 2982, 2983, 529, 529, 1858, - 2987, 3022, 1861, 2990, 2991, 295, 529, 295, 2995, 2996, - 529, 395, 2999, 436, 281, 123, 3003, 464, 473, 8, - 374, 1925, 11, 150, 473, 0, 15, 16, 3015, 521, - 26, 20, 21, 22, 37, 3013, 3013, 3013, 303, 528, - 3013, 374, 41, 3013, 3013, 255, 3557, 529, 3013, 3003, - 890, 2773, 2415, 2341, 1841, 2344, 266, 2786, 47, 3490, - 2720, 41, 61, 3638, 3589, 54, 3757, 3191, 278, 1954, - 867, 3091, 2504, 3003, 3061, 1979, 3613, 3730, 3357, 3670, - 3679, 61, 3069, 3723, 3415, 3003, 1243, 1991, 2332, 2350, - 1819, 1819, 81, 2851, 3668, 3677, 2763, 1579, 2792, 3665, - 310, 3088, 2329, 1376, 3664, 3762, 8, 3329, 107, 11, - 3097, 2499, 2421, 15, 16, 2500, 1348, 2021, 20, 21, - 22, 2868, 2309, 2826, 2028, 1035, 101, 107, 108, 2794, - 1035, 1196, 2275, 1801, 3068, 37, 1221, 2574, 118, 3647, - 2292, 1056, 1220, 3566, 1765, 3132, 3447, 1800, 23, 2069, - 3003, 1223, 2261, 3266, 1012, 365, 2519, 2925, 2521, 2555, - 2554, 3378, 2525, 2605, 2527, 1010, 3570, 2085, 2072, 3569, - 2169, 1010, 2076, 1010, 149, 1010, 1010, 1010, 2082, 1010, - 390, 1010, 2638, 1010, 2218, 2276, 2120, 3314, 2215, 164, - 179, 3178, 2662, 3015, 169, 1677, 2172, 1495, 178, 174, - 1890, 411, 2106, 3555, 3191, 204, 3013, 196, 183, 2974, - 804, 3198, 201, 188, 2078, 1738, 3178, 3204, 1000, 3195, - 1394, 3242, 2721, 180, 204, 1739, 3003, 3214, 3215, 3191, - 3217, 2090, 2517, 1874, -1, 224, 225, -1, -1, 3226, - 3227, 909, -1, -1, -1, 220, -1, -1, 205, -1, - -1, 240, -1, -1, -1, 3242, 255, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 241, 266, -1, -1, - -1, -1, -1, -1, -1, 255, -1, -1, -1, 278, - -1, -1, -1, -1, 3271, -1, 266, 244, -1, 8, - 3277, 280, 11, -1, 283, 0, 15, 16, 278, -1, - 280, 20, 21, 22, -1, -1, 3293, 3294, 297, -1, - 3297, 310, 3299, -1, -1, 20, -1, 292, 23, -1, - 295, -1, 224, -1, -1, -1, 301, -1, -1, -1, - 310, -1, 37, -1, -1, -1, -1, 1819, -1, -1, - -1, 46, -1, 300, 3331, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, - -1, 15, 16, 320, -1, -1, 365, 342, 3355, -1, - -1, -1, 77, 78, 79, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 365, -1, -1, -1, -1, - 2249, 390, 367, 47, -1, 297, -1, 3384, 103, 8, - 54, -1, 11, 56, -1, -1, 15, 16, -1, -1, - 390, 400, 411, -1, -1, -1, -1, -1, -1, -1, - 551, 3408, 379, 2282, 2283, 556, 2789, 81, 3404, 386, - -1, 411, 3366, 413, -1, 566, 416, -1, 47, -1, - -1, -1, -1, 1925, -1, 54, 3408, 3434, -1, -1, - 103, -1, 427, 3387, 3388, -1, 3443, -1, 3445, -1, - 3447, -1, -1, 2826, 3451, -1, 3453, -1, 3455, -1, - -1, 124, 81, -1, -1, 432, -1, 434, 3412, -1, - 3434, 456, 3469, -1, -1, -1, 153, 3474, 3475, 142, - -1, -1, 467, 147, 147, -1, -1, 1979, 2861, 3486, - 457, -1, -1, 460, 3434, 224, -1, 174, -1, 1991, - -1, 3487, 487, 3489, 489, 490, 3503, 170, -1, -1, - 173, 3508, -1, 512, -1, 179, 515, 516, 517, -1, - 519, 520, 521, 522, 523, 524, 189, 2441, 147, 2021, - -1, 3503, 196, -1, -1, -1, 2028, 201, 528, -1, - -1, 526, -1, -1, 529, 530, 531, 3533, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3556, - 179, -1, -1, -1, 3550, -1, -1, -1, 297, 3566, - -1, 3434, -1, -1, -1, -1, 240, 196, -1, -1, - 2072, 3578, 201, 2497, 2076, -1, -1, -1, -1, -1, - 2082, -1, -1, -1, -1, -1, 3593, -1, 3595, -1, - -1, -1, -1, 515, 516, 517, -1, 519, 520, 521, - 522, 523, 524, -1, 2106, -1, -1, 3614, 759, 760, - 761, 240, 285, -1, -1, -1, -1, -1, -1, 3593, - 293, -1, -1, 297, 3007, -1, -1, -1, -1, -1, - -1, 3638, -1, -1, 321, 322, 323, -1, -1, -1, - -1, -1, 315, 3593, -1, -1, 3653, -1, -1, -1, - -1, -1, 803, 804, -1, -1, -1, -1, 809, 3666, - 811, 3668, -1, -1, 3638, -1, -1, -1, 297, 820, - -1, -1, 345, 824, 825, -1, 827, -1, -1, 830, - 831, -1, -1, -1, 3691, -1, 3668, 3683, 3638, 2613, - -1, -1, 843, 844, 845, -1, -1, 848, 3705, 3706, - 3707, 388, -1, -1, 3658, 856, 857, 858, 859, 3716, - 861, -1, 863, 3709, -1, -1, -1, 3691, -1, -1, - 3593, -1, -1, -1, 875, -1, 400, -1, -1, -1, - 881, -1, -1, -1, 3741, -1, -1, -1, 2617, 2618, - 427, 3691, -1, 894, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 2678, -1, -1, 908, 909, -1, - -1, -1, -1, -1, -1, 3638, -1, -1, -1, -1, - -1, 400, -1, -1, -1, 462, 515, 516, 517, -1, - 519, 520, 521, 522, 523, 524, 473, -1, -1, 153, - -1, -1, -1, 3800, -1, -1, 947, 948, -1, -1, - 3807, -1, -1, 490, -1, -1, -1, 958, -1, -1, - 174, 962, 963, 964, 965, 966, -1, -1, 3691, -1, - 174, -1, -1, -1, -1, 550, -1, 514, 979, 25, + 2624, 2625, 1722, 1690, 1691, 1692, 529, 5, 1695, 532, + 1686, 299, 1699, 530, 316, 1702, 1703, 1704, 1705, 1706, + 1707, 1708, 1709, 1710, 529, 295, 1713, 532, 379, 1504, + 896, 1506, 898, 1720, 1509, 1722, 2624, 2625, 2626, 1514, + 529, 299, 1517, 532, 1519, 1066, 13, 14, 1523, 3348, + 1762, 38, 511, 1740, 173, 406, 532, 1692, 13, 14, + 528, 31, 529, 1762, 13, 14, 13, 14, 13, 14, + 174, 359, 529, 3348, 529, 363, 2510, 379, 1765, 248, + 13, 14, 13, 14, 2618, 300, 2620, 2621, 3451, 1776, + 1777, 13, 14, 13, 14, 222, 1196, 1738, 60, 248, + 248, 359, 13, 14, 406, 363, 528, 395, 428, 460, + 13, 14, 174, 515, 516, 517, 86, 519, 520, 521, + 522, 523, 524, 149, 511, 95, 2722, 13, 14, 127, + 128, 299, 1819, 13, 14, 13, 14, 395, 164, 13, + 14, 154, 1829, 169, 13, 14, 1833, 316, 226, 119, + 374, 375, 1173, 1829, 374, 375, 359, 1833, 460, 1466, + 1467, 374, 375, 374, 375, 1472, 154, 316, 316, 268, + 269, 3102, 384, 385, 13, 14, 174, 528, 472, 473, + 3739, 3740, 470, 2500, 2501, 3728, 3729, 1874, 175, 359, + 1877, 359, 3772, 3773, 220, 363, 154, 1884, 1874, 109, + 1887, 1888, 2320, 2321, 1176, 1177, 154, 41, 1066, 427, + 379, 154, 470, 154, 529, 241, 2745, 528, 480, 1066, + 280, 494, 90, 193, 211, 154, 528, 395, 154, 154, + 379, 379, 530, 154, 295, 1256, 206, 406, 1925, 361, + 227, 440, 1929, 2797, 1923, 528, 2841, 118, 2818, 528, + 2868, 238, 528, 429, 529, 47, 528, 406, 406, 2873, + 1947, 222, 3003, 227, 305, 528, 292, 1954, 1955, 528, + 227, 227, 302, 41, 239, 301, 1963, 2885, 528, 2685, + 2686, 5, 5, 528, 1384, 331, 1386, 3514, 3398, 528, + 528, 460, 1979, 528, 5, 5, 1983, 1984, 528, 1986, + 5, 528, 470, 174, 1991, 1992, 1993, 1994, 1995, 1996, + 1997, 460, 460, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007, 2008, 2009, 321, 322, 323, 3716, 5, 2015, 2016, + 3720, 528, 2019, 9, 2021, 528, 8, 528, 83, 2026, + 491, 2028, 532, 15, 16, 105, 532, 307, 20, 21, + 22, 529, 467, 395, 169, 222, 292, 169, 290, 528, + 60, 440, 239, 2050, 109, 528, 440, 94, 532, 75, + 2057, 440, 2059, 60, 60, 81, 2063, 440, 271, 528, + 528, 440, 19, 370, 528, 2072, 2057, 3686, 94, 2076, + 388, 2078, 2063, 2080, 224, 2082, 440, 440, 1256, 490, + 386, 399, 389, 154, 101, 1066, 2940, 2941, 3798, 1256, + 280, 3686, 118, 201, 120, 280, 280, 528, 41, 280, + 41, 2108, 2057, 280, 280, 423, 528, 174, 2063, 427, + 456, 176, 154, 2120, 2121, 530, 13, 529, 309, 529, + 2127, 3362, 174, 413, 532, 529, 416, 529, 529, 3093, + 321, 322, 323, 529, 529, 803, 528, 528, 487, 529, + 205, 2057, 227, 227, 462, 287, 287, 2063, 532, 477, + 528, 528, 40, 2160, 530, 473, 528, 2164, 528, 528, + 528, 528, 2169, 2170, 2200, 486, 9, 835, 528, 11, + 528, 527, 490, 532, 2900, 361, 438, 3105, 3106, 3609, + 438, 2935, 19, 209, 249, 532, 537, 285, 2195, 2196, + 438, 528, 860, 2200, 2057, 183, 514, 388, 165, 174, + 2063, 2927, 440, 532, 529, 174, 229, 41, 467, 2216, + 528, 3667, 2219, 2220, 2221, 220, 532, 467, 27, 3207, + 271, 229, 296, 398, 33, 319, 319, 532, 3658, 532, + 2237, 2238, 41, 183, 529, 222, 427, 2244, 1579, 3093, + 2247, 909, 359, 229, 3098, 528, 149, 280, 229, 60, + 60, 530, 61, 2979, 280, 60, 2263, 60, 287, 285, + 2267, 164, 2057, 301, 340, 2220, 169, 3421, 2063, 287, + 2277, 462, 529, 480, 293, 1256, 2267, 154, 3, 154, + 154, 528, 473, 3713, 3514, 528, 154, 2294, 2295, 154, + 154, 490, 2247, 532, 41, 532, 280, 3, 107, 490, + 295, 295, 41, 60, 2311, 297, 2313, 174, 2263, 335, + 11, 41, 2267, 169, 379, 529, 528, 220, 529, 529, + 3074, 2328, 183, 514, 529, 390, 528, 353, 169, 138, + 3, 2247, 1000, 528, 526, 2342, 1677, 528, 241, 3, + 309, 40, 1010, 526, 2351, 2352, 2353, 2263, 526, 440, + 3076, 2267, 321, 322, 323, 2351, 2352, 2353, 440, 440, + 529, 440, 427, 527, 529, 1992, 1993, 1994, 1995, 1996, + 1997, 529, 532, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007, 2008, 2009, 530, 2247, 537, 451, 511, 511, 292, + 2397, 149, 529, 3331, 1814, 204, 529, 359, 301, 2406, + 2263, 1579, 529, 529, 2267, 1825, 164, 1827, 530, 150, + 1830, 169, 1579, 529, 529, 480, 511, 528, 174, 388, + 1840, 528, 1842, 528, 440, 528, 157, 528, 487, 41, + 60, 457, 2439, 532, 517, 1855, 513, 2444, 3689, 296, + 1860, 467, 2425, 2439, 1864, 1865, 255, 1867, 2425, 1869, + 1870, 296, 2247, 464, 2425, 2425, 247, 266, 427, 532, + 153, 60, 220, 60, 1132, 3191, 479, 271, 2263, 278, + 440, 56, 2267, 280, 1142, 440, 154, 205, 1819, 528, + 154, 174, 154, 241, 440, 517, 440, 3341, 3342, 528, + 299, 2498, 528, 462, 3348, 2502, 1164, 41, 440, 1677, + 440, 310, 529, 41, 473, 1173, 528, 3381, 3382, 361, + 1677, 2518, 490, 528, 41, 529, 154, 3047, 103, 528, + 532, 490, 2518, 515, 516, 517, 528, 519, 520, 521, + 522, 523, 524, 3407, 292, 3409, 285, 3453, 529, 124, + 174, 60, 188, 301, 529, 514, 528, 14, 528, 2556, + 359, 169, 529, 456, 363, 529, 365, 142, 529, 528, + 81, 529, 147, 526, 144, 526, 532, 174, 2195, 2196, + 3419, 529, 19, 306, 529, 254, 529, 528, 367, 296, + 529, 390, 528, 183, 1925, 170, 395, 532, 173, 154, + 529, 2598, 528, 528, 532, 529, 529, 528, 1579, 178, + 451, 2556, 411, 529, 189, 529, 529, 3422, 2615, 3424, + 530, 2628, 528, 1281, 528, 528, 41, 60, 60, 295, + 2656, 41, 293, 526, 41, 41, 2633, 530, 321, 322, + 323, 467, 532, 2640, 2641, 174, 528, 201, 1979, 41, + 2556, 1819, 529, 489, 529, 529, 527, 527, 527, 2656, + 1991, 473, 1819, 529, 532, 2691, 2696, 529, 529, 61, + 529, 470, 2669, 295, 517, 2672, 532, 2674, 3522, 3523, + 486, 60, 490, 207, 2681, 2682, 3614, 118, 2685, 2686, + 2021, 529, 529, 2690, 2691, 3673, 41, 2028, 229, 529, + 2697, 3417, 89, 2556, 529, 388, 1677, 528, 456, 194, + 285, 285, 285, 517, 3623, 107, 108, 2714, 293, 2745, + 529, 3601, 527, 440, 440, 527, 118, 41, 2725, 2718, + 280, 529, 87, 529, 108, 490, 295, 529, 528, 528, + 315, 2072, 528, 528, 427, 2076, 529, 427, 2745, 9, + 532, 2082, 1410, 528, 360, 3594, 528, 1925, 528, 532, + 342, 532, 529, 60, 529, 201, 527, 527, 1925, 532, + 345, 529, 194, 529, 472, 532, 92, 2108, 526, 462, + 529, 529, 530, 528, 41, 353, 178, 154, 529, 125, + 473, 154, 2789, 41, 529, 2792, 2793, 2794, 41, 2796, + 2797, 2798, 529, 2789, 528, 41, 8, 490, 2794, 11, + 2796, 1979, 204, 15, 16, 2812, 2813, 528, 20, 21, + 22, 467, 1979, 1991, 532, 528, 315, 37, 2825, 253, + 285, 514, 252, 528, 1991, 193, 467, 530, 530, 2836, + 2866, 529, 3686, 530, 530, 528, 2835, 2844, 1819, 2259, + 375, 530, 530, 2021, 2880, 530, 530, 530, 530, 530, + 2028, 528, 375, 255, 2021, 530, 75, 2840, 298, 75, + 530, 2028, 41, 2840, 266, 530, 2873, 530, 530, 2840, + 2840, 2870, 530, 530, 81, 530, 278, 530, 280, 530, + 530, 530, 61, 530, 9, 530, 530, 530, 530, 528, + 530, 2927, 529, 2900, 2072, 530, 2903, 530, 2076, 530, + 529, 3655, 530, 153, 2082, 2072, 530, 529, 310, 2076, + 529, 377, 527, 2920, 2921, 2082, 2923, 527, 60, 94, + 2927, 134, 436, 2930, 174, 60, 517, 278, 107, 295, + 2108, 7, 8, 41, 528, 298, 298, 13, 528, 472, + 529, 2108, 529, 19, 1925, 207, 295, 23, 529, 25, + 295, 451, 2959, 29, 30, 31, 529, 395, 34, 3833, + 281, 37, 38, 365, 436, 41, 123, 464, 44, 45, + 451, 374, 2979, 174, 150, 473, 521, 2984, 2985, 473, + 26, 37, 2989, 2990, 374, 528, 303, 2994, 390, 201, + 2997, 2998, 529, 3029, 890, 3002, 3003, 2776, 1979, 3006, + 2343, 77, 78, 3010, 2346, 1841, 2789, 3455, 3658, 411, + 1991, 413, 224, 2723, 416, 3022, 3605, 3782, 3150, 3010, + 1954, 3020, 3098, 2505, 3686, 204, 3629, 103, 3020, 867, + 3752, 3020, 2452, 3020, 110, 111, 112, 113, 114, 115, + 2021, 3324, 3020, 3573, 3020, 3020, 38, 2028, 3690, 3745, + 3699, 43, 3379, 2334, 2352, 3010, 1819, 1819, 2685, 2686, + 3688, 3068, 1730, 1243, 3697, 2766, 2796, 8, 2855, 3076, + 11, 321, 322, 323, 15, 16, 255, 2331, 3685, 1376, + 3684, 3787, 3296, 2500, 1348, 297, 2501, 266, 3095, 2873, + 2424, 2072, 2311, 2830, 3010, 2076, 1196, 3104, 1035, 278, + 2798, 2082, 2277, 2444, 1801, 1035, 47, 1221, 2575, 3667, + 102, 1220, 1056, 54, 2294, 1765, 3582, 3411, 1800, 1223, + 321, 322, 323, 23, 2263, 2930, 528, 2108, 2069, 3231, + 3137, 310, 2556, 2555, 2606, 3345, 1804, 1805, 388, 1012, + 81, 3137, 2086, 3150, 3586, 3585, 2171, 3010, 1010, 2641, + 3157, 1010, 1010, 2278, 3150, 3154, 1010, 2498, 3281, 2220, + 1010, 1010, 3169, 2217, 1495, 1833, 1010, 2122, 2174, 2665, + 3571, 3207, 3179, 3180, 2981, 3182, 3022, 427, 1010, 804, + 1010, 3020, 41, 175, 3191, 3192, 365, 388, 1890, 2078, + 0, 1394, 1738, 909, 2724, 2518, 1739, 1874, -1, 1000, + 3207, -1, 61, 1871, -1, -1, 147, -1, -1, -1, + 20, 390, 462, 23, -1, 3010, -1, -1, -1, 211, + -1, 1889, 1890, 473, -1, -1, 427, 37, 127, 128, + 3237, -1, 411, -1, -1, 227, 46, 3244, 179, -1, + 490, -1, -1, -1, -1, -1, 238, -1, 107, -1, + -1, -1, -1, 3260, 3261, 196, -1, 3264, 38, 3266, + 201, 462, -1, 43, 514, -1, 2444, 77, 78, 79, + -1, -1, 473, 2900, 2615, 174, -1, 2444, 528, -1, + -1, -1, 274, -1, -1, -1, -1, -1, -1, 490, + -1, 3298, -1, 103, -1, -1, -1, -1, -1, 240, + -1, 1969, -1, 515, 516, 517, -1, 519, 520, 521, + 522, 523, 524, 514, -1, 3322, -1, -1, -1, 178, + 2498, -1, 102, -1, -1, -1, -1, 528, 2748, 321, + -1, 2498, 2752, -1, -1, 0, 328, -1, -1, -1, + 2681, 3348, -1, -1, -1, 204, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 297, -1, -1, -1, + -1, 2781, -1, -1, -1, 3372, -1, -1, -1, 3368, + -1, -1, -1, -1, 3381, 3382, 3372, -1, 370, 2799, + 2800, 2801, 2802, -1, 2804, 2805, 2806, 2807, 2808, -1, + -1, 3398, -1, -1, -1, 175, 255, 389, -1, -1, + 3407, -1, 3409, 183, 3411, -1, -1, 266, 3415, -1, + 3417, -1, 3419, -1, -1, -1, -1, -1, -1, 278, + -1, -1, 321, 322, 323, -1, -1, 3434, -1, -1, + -1, 211, 3439, 3440, -1, -1, 101, 2615, -1, -1, + -1, -1, -1, 3398, 3451, -1, -1, 227, 2615, 3076, + -1, 310, -1, 3452, -1, 3454, -1, -1, 238, 400, + -1, 3468, -1, 2444, -1, -1, 3473, -1, -1, -1, + 462, -1, 3468, -1, -1, 551, -1, -1, -1, -1, + 556, -1, 3398, -1, 149, -1, -1, -1, -1, 388, + 566, -1, -1, -1, 274, 2836, -1, -1, -1, 164, + 399, -1, -1, 2681, 169, -1, 365, 3514, -1, 174, + -1, -1, -1, -1, 2681, 295, -1, 2498, 183, -1, + -1, -1, -1, 188, 423, -1, -1, -1, 427, -1, + -1, 390, -1, -1, -1, 3398, -1, -1, -1, -1, + -1, 321, -1, -1, -1, -1, 3545, -1, 328, -1, + -1, -1, 411, -1, -1, 220, -1, -1, -1, -1, + -1, -1, 2903, 462, 3191, 3572, -1, 3566, -1, -1, + -1, 512, -1, -1, 473, 3582, 241, -1, 519, 520, + 521, 522, 523, 524, -1, 8, -1, 3594, 11, -1, + 370, 490, 15, 16, -1, -1, -1, 20, 21, 22, + -1, -1, 3609, -1, 3611, -1, -1, -1, -1, 389, + -1, -1, -1, 1066, -1, 514, -1, -1, -1, -1, + -1, -1, -1, 3630, -1, -1, -1, 292, -1, 528, + 295, -1, 8, -1, 2615, 11, 301, -1, -1, 15, + 16, -1, -1, -1, 20, 21, 22, -1, -1, 2990, + 180, 3658, -1, -1, 3609, 3075, -1, -1, 2836, -1, + -1, 37, -1, -1, -1, -1, 3673, -1, -1, 2836, + -1, -1, -1, -1, -1, 205, -1, 342, -1, 3686, + -1, 3688, 462, 759, 760, 761, -1, 467, -1, -1, + 2358, -1, 3688, 3609, -1, -1, -1, -1, -1, -1, + 2681, -1, 367, 3658, -1, 3704, 3713, -1, -1, -1, + -1, -1, -1, -1, 244, -1, -1, -1, -1, -1, + 3727, 3728, 3729, -1, -1, 2903, -1, 803, 804, -1, + -1, 3738, 3731, 809, -1, 811, 2903, -1, -1, -1, + 550, -1, 3658, -1, 820, -1, 3609, -1, 824, 825, + 2418, 827, -1, -1, 830, 831, -1, -1, 3713, 3766, + -1, -1, 427, 3104, -1, -1, -1, 843, 844, 845, + 300, -1, 848, -1, -1, -1, -1, -1, 201, -1, + 856, 857, 858, 859, -1, 861, -1, 863, -1, -1, + 320, 456, -1, -1, -1, 3658, -1, 3713, -1, 875, + -1, 224, 467, 1256, -1, 881, -1, -1, -1, -1, + -1, -1, 2990, -1, -1, -1, 3157, -1, 894, 3826, + -1, -1, 487, 2990, 489, 490, 3833, -1, 3169, -1, + -1, -1, 908, 909, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 224, 379, + 3713, 3192, 2520, -1, 2522, 2836, 386, -1, 2526, -1, + 2528, 526, -1, -1, 529, 530, 531, -1, -1, -1, + -1, 947, 948, -1, 297, -1, -1, -1, -1, -1, + -1, -1, 958, -1, -1, -1, 962, 963, 964, 965, + 966, -1, -1, -1, 0, -1, 3237, -1, -1, -1, + -1, -1, 432, 979, 434, -1, -1, -1, -1, -1, + -1, -1, -1, 3333, -1, -1, -1, -1, -1, -1, + -1, 297, 2903, -1, -1, -1, 3104, 457, -1, -1, + 460, 3351, 3352, -1, -1, 1011, 1012, 3104, 1014, -1, + -1, 1017, -1, -1, -1, -1, -1, 1023, 1024, -1, + -1, -1, -1, -1, 1030, -1, 3376, 767, 768, -1, + 1036, -1, 1038, -1, -1, 38, -1, -1, -1, -1, + 43, 1047, -1, -1, -1, -1, -1, -1, -1, 3157, + -1, 1057, -1, -1, -1, -1, -1, -1, -1, -1, + 3157, 3169, -1, -1, -1, 101, -1, -1, 1074, 809, + -1, -1, 3169, -1, -1, -1, -1, 3348, -1, 2990, + 820, -1, -1, -1, 3192, -1, -1, 827, -1, -1, + -1, -1, -1, -1, -1, 3192, 1102, -1, 1066, 102, + -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, + -1, -1, 1066, 149, -1, -1, -1, -1, -1, -1, + -1, 1127, -1, -1, -1, -1, -1, -1, 164, 3237, + -1, -1, 872, 169, -1, -1, -1, -1, 174, -1, + 3237, -1, -1, -1, -1, -1, -1, 183, -1, -1, + 890, -1, 188, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, + 523, 524, 175, -1, 1180, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 220, -1, -1, -1, -1, -1, + 1196, 1197, -1, 3104, -1, -1, 1579, 1203, 2796, -1, + 1206, -1, -1, -1, 101, 241, -1, -1, 211, 515, + 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, + -1, 1227, 1228, 1229, 227, 99, -1, -1, -1, -1, + -1, 1237, 2830, -1, 1240, 238, 1242, 1243, -1, -1, + 3348, -1, -1, 3514, -1, -1, 3157, -1, -1, 1255, + -1, 3348, 149, 127, 128, -1, 292, -1, 3169, 295, + -1, -1, -1, 1003, -1, 301, 1272, 164, 2866, -1, + 1276, 274, 169, -1, -1, -1, 1282, 174, -1, -1, + -1, 3192, -1, -1, -1, -1, 183, -1, 1256, -1, + -1, 188, 295, -1, 1677, -1, 1036, -1, 1038, -1, + 174, -1, 1256, -1, -1, -1, 342, 1047, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 321, -1, + -1, -1, -1, 220, -1, 328, 3237, -1, 3678, -1, + -1, 367, -1, -1, -1, -1, -1, -1, 1344, -1, + 1346, -1, 1082, -1, 241, -1, -1, -1, 1354, -1, + -1, -1, -1, -1, 1094, -1, -1, -1, -1, -1, + -1, 1367, -1, -1, 37, -1, -1, 370, 41, -1, + 1376, -1, -1, -1, -1, 1381, -1, 1383, 1384, -1, + 1386, 1387, -1, 1123, -1, -1, 389, -1, -1, -1, + -1, 427, -1, -1, -1, 292, -1, -1, 295, -1, + -1, -1, -1, -1, 301, -1, 3514, -1, -1, -1, + -1, -1, -1, -1, -1, 3686, 3014, 3514, -1, -1, + 456, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 103, 467, -1, -1, -1, -1, 1819, 3348, 111, -1, + 113, -1, 115, -1, -1, 342, -1, 321, 322, 323, + -1, 487, -1, 489, 490, -1, -1, -1, -1, 462, + 1466, 1467, -1, -1, 467, -1, 1472, -1, 1474, -1, + 367, 1211, 1212, -1, 1214, -1, -1, -1, -1, -1, + -1, 1487, -1, 1489, 1490, -1, -1, -1, 1494, 1495, + 526, 1497, -1, 529, 530, 531, -1, -1, 1504, -1, + 1506, -1, -1, 1509, -1, -1, -1, -1, 1514, -1, + 1516, 1517, -1, 1519, 388, -1, -1, 1523, -1, 1525, + -1, 1527, -1, -1, -1, 399, -1, -1, -1, 8, + 427, -1, 11, -1, -1, -1, 15, 16, -1, -1, + -1, -1, 1925, -1, -1, -1, -1, -1, -1, 423, + -1, -1, -1, 427, -1, -1, -1, -1, -1, 456, + -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, + 467, -1, -1, -1, 448, 54, -1, -1, 3686, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 462, 3686, + 487, -1, 489, 490, -1, -1, 1979, -1, -1, 473, + -1, -1, 81, 3514, -1, -1, -1, -1, 1991, -1, + -1, 1579, -1, -1, -1, -1, 490, -1, -1, -1, + -1, -1, -1, -1, -1, 1579, -1, -1, -1, 526, + 1636, -1, 529, 530, 531, -1, -1, -1, 2021, -1, + 514, -1, 13, 1649, -1, 2028, -1, -1, 19, -1, + -1, -1, 23, 1393, 528, -1, -1, 8, -1, 30, + 11, -1, -1, -1, 15, 16, -1, -1, 147, -1, + -1, -1, -1, 44, 45, -1, -1, -1, -1, 3277, + -1, -1, -1, 1689, -1, -1, 1692, -1, -1, 2072, + -1, -1, -1, 2076, -1, -1, 47, -1, -1, 2082, + 179, -1, -1, 54, -1, -1, 77, 78, -1, 1677, + -1, -1, -1, -1, 1720, -1, -1, 196, -1, -1, + -1, -1, 201, 1677, -1, 2108, -1, -1, -1, 1735, + 81, 1737, 8, 1739, -1, 11, -1, -1, -1, 15, + 16, 112, -1, -1, 1750, -1, -1, 1753, -1, -1, + 3348, -1, -1, -1, -1, -1, -1, -1, -1, 1765, + -1, 240, -1, -1, 1504, -1, 1506, -1, -1, 1509, + -1, 47, -1, -1, 1514, 3686, -1, 1517, 54, 1519, + -1, -1, -1, 1523, 1790, -1, 1792, -1, -1, -1, + 3388, -1, -1, -1, -1, -1, 147, -1, 1804, 1805, + -1, -1, -1, -1, 1810, 81, -1, 1813, 1814, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 297, 1825, + 1826, 1827, 1828, -1, 1830, -1, -1, -1, 179, -1, + -1, -1, -1, -1, 1840, -1, 1842, -1, -1, -1, + -1, -1, -1, -1, -1, 196, -1, -1, 1854, 1855, + 201, 1819, -1, 1859, 1860, -1, -1, -1, 1864, 1865, + 1866, 1867, -1, 1869, 1870, 1819, -1, -1, -1, 1609, + -1, 147, -1, -1, -1, -1, -1, -1, 551, -1, + -1, -1, -1, 556, -1, 1891, -1, -1, -1, 240, + -1, -1, -1, 1899, -1, 1901, 1902, 1903, 1904, 1905, + 1906, -1, -1, 179, 8, -1, -1, 11, -1, -1, + -1, 15, 16, 17, 18, 1921, 20, 21, 22, -1, + 196, 400, -1, -1, -1, 201, -1, -1, -1, -1, + -1, -1, -1, 37, -1, -1, 1942, -1, -1, 3537, + -1, -1, -1, 47, 38, -1, 297, -1, -1, 43, + 54, -1, 1692, -1, -1, -1, -1, 1925, -1, -1, + -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, + -1, 1925, -1, -1, -1, -1, -1, 81, -1, -1, + -1, -1, -1, -1, -1, -1, 1992, 1993, 1994, 1995, + 1996, 1997, -1, -1, 2000, 2001, 2002, 2003, 2004, 2005, + 2006, 2007, 2008, 2009, -1, -1, -1, -1, 102, -1, + -1, 1979, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 297, 1762, 1991, 2030, 1979, -1, -1, -1, -1, + -1, -1, -1, 512, -1, -1, -1, 1991, 2044, -1, + 519, 520, 521, 522, 523, 524, -1, -1, -1, 400, + -1, 2057, -1, 2021, -1, -1, -1, 2063, -1, -1, + 2028, 2444, -1, 2069, -1, -1, -1, 2021, -1, 2075, + -1, -1, -1, -1, 2028, 179, -1, -1, -1, 2085, + 2086, 175, -1, -1, -1, -1, -1, -1, 3686, -1, + -1, -1, 196, -1, -1, -1, -1, 201, -1, -1, + -1, -1, -1, -1, 2072, -1, -1, -1, 2076, -1, + -1, -1, -1, -1, 2082, 2498, -1, 211, 2072, -1, + 224, 225, 2076, -1, 400, -1, -1, -1, 2082, -1, + -1, -1, -1, 227, -1, -1, 240, -1, 811, -1, + 2108, -1, -1, -1, 238, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2108, 2161, -1, -1, -1, -1, + 2166, 512, -1, -1, -1, 2171, -1, -1, 519, 520, + 521, 522, 523, 524, -1, -1, 280, -1, 8, 283, + 274, 11, -1, 1923, -1, 15, 16, -1, -1, 2195, + 2196, -1, -1, 297, -1, 566, 300, -1, -1, -1, + -1, 295, -1, -1, -1, -1, -1, -1, 2214, -1, + -1, -1, -1, -1, 2220, -1, -1, 47, -1, -1, + -1, -1, -1, -1, 54, -1, -1, 321, -1, -1, + -1, -1, 2615, -1, 328, 908, 512, -1, -1, -1, + -1, 2247, -1, 519, 520, 521, 522, 523, 524, -1, + -1, 81, 8, 2259, -1, 11, -1, 2263, -1, 15, + 16, 2267, 2268, -1, 20, 21, 22, -1, -1, -1, + -1, -1, -1, 1017, 947, -1, 370, -1, -1, -1, + -1, 37, -1, -1, -1, -1, -1, -1, -1, 962, + 963, 964, 965, 966, -1, 389, 400, -1, 2681, -1, + -1, -1, 2308, -1, -1, 2311, 8, 2313, 2314, 11, + -1, -1, -1, 15, 16, -1, -1, 2057, 20, 21, + 22, -1, -1, 2063, -1, -1, 8, -1, -1, 11, + 2336, -1, -1, 15, 16, -1, -1, -1, 20, 21, + 22, 1014, -1, -1, -1, 47, -1, -1, -1, 179, + -1, 8, 54, -1, 11, 37, -1, -1, 15, 16, + -1, -1, -1, 20, 21, 22, 196, -1, 462, -1, + -1, 201, -1, -1, -1, -1, -1, -1, -1, 81, + 37, -1, -1, -1, -1, -1, -1, -1, -1, 760, + 761, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 512, -1, - -1, 528, -1, -1, -1, 519, 520, 521, 522, 523, - 524, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1011, 1012, -1, 1014, -1, 2789, 1017, -1, -1, -1, - -1, -1, 1023, 1024, -1, -1, -1, -1, -1, 1030, - -1, -1, -1, 512, -1, 1036, 82, 1038, -1, -1, - 519, 520, 521, 522, 523, 524, 1047, 8, -1, -1, - 11, -1, 98, -1, 15, 16, 1057, -1, 2832, -1, - 2789, -1, -1, -1, -1, -1, -1, 8, -1, -1, - 11, -1, -1, 1074, 15, 16, -1, 3310, -1, 20, - 21, 22, -1, -1, -1, -1, 47, -1, -1, 2441, - -1, -1, -1, 54, -1, -1, 37, -1, 1066, -1, - -1, 1102, 148, 1066, -1, 309, 47, 321, 322, 323, - -1, -1, 158, 54, -1, -1, -1, 321, 322, 323, - 81, -1, -1, -1, 2898, 171, 1127, -1, -1, -1, - 176, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 81, -1, -1, -1, -1, 2497, -1, -1, -1, -1, - -1, 3384, -1, -1, -1, -1, -1, -1, 8, 205, - -1, 11, -1, -1, -1, 15, 16, -1, -1, -1, - 20, 21, 22, -1, 388, -1, -1, -1, -1, 1180, - -1, -1, -1, -1, 388, -1, 147, -1, -1, -1, - -1, 3424, 767, 768, -1, 1196, 1197, 47, -1, -1, - -1, -1, 1203, 249, 54, 1206, 2935, -1, 254, 2983, - -1, -1, -1, 427, -1, -1, -1, -1, 179, -1, - -1, -1, -1, 427, -1, -1, 1227, 1228, 1229, -1, - -1, 81, -1, -1, 809, 196, 1237, -1, 179, 1240, - 201, 1242, 1243, -1, -1, 820, -1, -1, 462, -1, - -1, -1, 827, -1, 1255, 196, -1, -1, 462, 473, - 201, 2613, -1, -1, -1, -1, -1, -1, -1, 473, - -1, 1272, -1, -1, 320, 1276, 490, -1, -1, 240, - 326, 1282, -1, 224, 225, 1066, 490, -1, 1256, -1, - -1, -1, 3525, 1256, -1, 341, -1, 872, -1, 240, - 514, -1, -1, -1, -1, 127, 128, -1, -1, -1, - 514, -1, -1, -1, 528, 890, -1, -1, -1, -1, - -1, -1, -1, 3097, 528, -1, 2678, -1, -1, 179, - 376, -1, -1, 379, -1, -1, 297, -1, -1, 280, - -1, -1, 283, 1344, 390, 1346, 196, 393, -1, -1, - -1, 201, 174, 1354, -1, -1, 297, 3086, 3132, 300, - -1, -1, 3091, -1, -1, -1, 1367, 413, -1, -1, - -1, -1, -1, -1, -1, 1376, -1, -1, -1, -1, - 1381, 427, 1383, 1384, -1, 1386, 1387, -1, 434, 435, - 240, -1, -1, -1, -1, -1, -1, -1, -1, 445, - -1, -1, -1, -1, -1, 451, -1, -1, -1, -1, - -1, 3140, 3141, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3198, -1, -1, -1, 1003, -1, - 3204, -1, -1, 3666, 480, -1, -1, 2789, -1, 400, - -1, -1, -1, -1, -1, -1, -1, 297, -1, -1, - -1, -1, -1, 3227, -1, -1, -1, -1, -1, 400, - -1, 1036, -1, 1038, -1, 1466, 1467, -1, -1, -1, - -1, 1472, 1047, 1474, -1, 1256, -1, -1, -1, -1, - 2832, -1, -1, -1, -1, -1, 1487, -1, 1489, 1490, - -1, -1, -1, 1494, 1495, -1, 1497, 3271, -1, 321, - 322, 323, -1, 1504, 38, 1506, -1, 1082, 1509, 43, - -1, -1, -1, 1514, -1, 1516, 1517, -1, 1519, 1094, - -1, -1, 1523, -1, 1525, -1, 1527, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 2898, -1, 1123, -1, - 400, 512, -1, -1, -1, -1, -1, -1, 519, 520, - 521, 522, 523, 524, -1, -1, 388, -1, 102, -1, - -1, 512, -1, -1, 515, 516, 517, 399, 519, 520, - 521, 522, 523, 524, 8, -1, -1, 11, -1, -1, - -1, 15, 16, -1, -1, -1, -1, -1, -1, -1, - -1, 423, -1, -1, -1, 427, -1, -1, -1, -1, - 3384, 1579, -1, -1, -1, -1, 1579, 8, -1, -1, - 11, -1, -1, 47, 15, 16, -1, -1, -1, -1, - 54, 2983, -1, -1, -1, 1636, 1211, 1212, -1, 1214, - 462, 175, -1, -1, -1, 3374, 3375, -1, 1649, 183, - -1, 473, -1, -1, -1, 3384, 47, 81, -1, -1, - -1, -1, 512, 54, -1, 515, 516, 517, 490, 519, - 520, 521, 522, 523, 524, -1, -1, 211, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1066, 1689, -1, - 81, 1692, 514, 227, 38, -1, -1, -1, -1, 43, - -1, -1, -1, -1, 238, -1, 528, -1, -1, 1677, - -1, -1, -1, -1, 1677, -1, -1, -1, -1, 1720, - -1, -1, -1, 147, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 1735, -1, 1737, -1, 1739, -1, - 274, -1, -1, -1, -1, 3097, -1, -1, -1, 1750, - -1, -1, 1753, -1, -1, 179, 147, -1, 102, -1, - -1, 295, 8, -1, 1765, 11, -1, -1, -1, 15, - 16, -1, 196, -1, 20, 21, 22, 201, -1, -1, - 3132, -1, -1, -1, -1, -1, -1, 321, 179, 1790, - -1, 1792, -1, -1, 328, -1, -1, -1, 1579, -1, - -1, -1, -1, 1804, 1805, 196, -1, -1, 1066, 1810, - 201, -1, 1813, 1814, -1, -1, 240, -1, 1393, -1, - -1, -1, -1, -1, 1825, 1826, 1827, 1828, -1, 1830, - -1, 175, -1, -1, -1, -1, 370, -1, -1, 1840, - -1, 1842, -1, -1, -1, -1, 3198, -1, -1, 240, - -1, 1819, 3204, 1854, 1855, 389, 1819, -1, 1859, 1860, - -1, -1, -1, 1864, 1865, 1866, 1867, 211, 1869, 1870, - -1, -1, -1, 297, -1, 3227, -1, 1256, -1, -1, - 37, -1, -1, 227, 41, -1, -1, -1, -1, -1, - 1891, -1, 3666, -1, 238, -1, 1677, -1, 1899, -1, - 1901, 1902, 1903, 1904, 1905, 1906, 297, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3271, - 1921, -1, -1, -1, -1, -1, -1, -1, 462, 1504, - 274, 1506, -1, 467, 1509, -1, -1, 3666, -1, 1514, - -1, 1942, 1517, -1, 1519, -1, 103, -1, 1523, -1, - -1, 295, -1, -1, 111, -1, 113, 1925, 115, -1, - -1, -1, 1925, -1, -1, 1017, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 400, 321, 224, -1, - -1, -1, -1, -1, 328, -1, -1, -1, -1, -1, - -1, 1992, 1993, 1994, 1995, 1996, 1997, -1, 1256, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 400, - -1, 1979, -1, -1, -1, -1, 1979, -1, -1, -1, - -1, -1, -1, 1991, -1, -1, 370, -1, 1991, 2030, - -1, -1, 3384, -1, 1609, -1, -1, -1, 1819, -1, - -1, -1, -1, 2044, -1, 389, -1, -1, -1, -1, - -1, 297, -1, 2021, -1, -1, 2057, -1, 2021, -1, - 2028, -1, 2063, -1, -1, 2028, -1, -1, 2069, -1, - -1, -1, -1, -1, 2075, -1, -1, -1, -1, -1, - -1, -1, -1, 2084, 2085, -1, -1, -1, 512, -1, - -1, -1, -1, -1, -1, 519, 520, 521, 522, 523, - 524, -1, -1, -1, 2072, 13, -1, -1, 2076, 2072, - -1, 19, -1, 2076, 2082, 23, -1, 1692, 462, 2082, - -1, 512, 30, 467, -1, -1, -1, -1, 519, 520, - 521, 522, 523, 524, -1, -1, 44, 45, 2106, -1, - -1, -1, -1, 2106, 1925, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2159, -1, - -1, -1, -1, 2164, -1, -1, 1218, -1, 2169, 77, - 78, -1, -1, -1, -1, 1227, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1762, -1, -1, - -1, -1, 2193, 2194, -1, -1, -1, -1, 1979, -1, - 1579, -1, -1, -1, 112, -1, -1, -1, -1, -1, - 1991, 2212, -1, -1, -1, -1, -1, 2218, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2021, -1, -1, -1, 2245, -1, -1, 2028, -1, -1, - -1, -1, -1, -1, -1, -1, 2257, -1, -1, -1, - 2261, -1, -1, -1, 2265, 2266, -1, -1, -1, 515, + 240, 515, 516, 517, 2420, 519, 520, 521, 522, 523, + 524, 2427, -1, -1, -1, -1, -1, -1, 532, -1, + -1, 2437, -1, -1, 2440, 2441, 2442, 2443, -1, -1, + -1, -1, -1, -1, -1, -1, 2452, -1, 2454, 820, + -1, -1, 2458, 2836, -1, 2461, -1, -1, -1, -1, + 2200, -1, -1, -1, -1, -1, -1, 297, 224, -1, + -1, -1, -1, -1, -1, -1, 2444, 179, -1, -1, + 2220, -1, -1, 1227, -1, -1, -1, -1, -1, -1, + 2444, -1, -1, -1, 196, -1, 2236, -1, 2504, 201, + -1, -1, -1, -1, 2510, -1, -1, 2247, -1, -1, + 881, -1, -1, -1, -1, -1, -1, -1, 2524, 2525, + 2903, 2527, -1, 2263, -1, -1, -1, 2267, -1, -1, + 2498, -1, -1, -1, -1, -1, -1, -1, 240, -1, + -1, 297, 224, -1, 2498, -1, -1, -1, -1, -1, + 2556, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 1237, -1, -1, 224, 2574, 1242, + 400, -1, 8, -1, -1, 11, 2582, 2583, 2584, 15, + 16, -1, 1255, -1, 20, 21, 22, -1, -1, -1, + 2596, -1, 2598, -1, 2600, 297, -1, -1, -1, -1, + 2606, -1, -1, 1276, -1, -1, -1, 2990, -1, -1, + -1, -1, -1, -1, -1, 297, -1, -1, -1, -1, + -1, -1, 2628, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2643, -1, -1, + 297, -1, -1, -1, -1, -1, -1, 2615, -1, 2655, + -1, -1, -1, 2659, -1, -1, -1, -1, -1, 1030, + -1, 2615, -1, -1, -1, 1036, -1, 1038, -1, -1, + -1, -1, -1, 1346, -1, -1, 1047, -1, -1, 2685, + 2686, 1354, 512, -1, -1, -1, 1057, -1, -1, 519, + 520, 521, 522, 523, 524, -1, -1, -1, 400, -1, + -1, -1, -1, 2709, -1, -1, -1, -1, -1, -1, + 2716, -1, -1, 2681, -1, 2455, -1, 2723, -1, -1, + -1, 3104, 1466, 1467, -1, -1, -1, 2681, 1472, -1, + -1, 1102, -1, 2739, -1, -1, -1, 2743, -1, 2745, + -1, 2747, 2748, -1, -1, 2751, 2752, -1, -1, -1, + 2756, 2757, 2758, -1, 2760, -1, 1127, -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, + -1, -1, -1, -1, 3157, 2781, -1, 2783, -1, -1, + -1, -1, -1, -1, -1, -1, 3169, -1, 224, -1, + -1, -1, -1, 2799, 2800, 2801, 2802, 2803, 2804, 2805, + 2806, 2807, 2808, -1, -1, -1, -1, -1, -1, 3192, + 512, -1, -1, 515, 516, 517, -1, 519, 520, 521, + 522, 523, 524, -1, 1497, 1196, 1197, -1, 2834, -1, + -1, -1, -1, 515, 516, 517, 2842, 519, 520, 521, + 522, 523, 524, -1, -1, -1, -1, -1, -1, 2855, + -1, -1, -1, -1, 3237, -1, -1, -1, 515, 516, + 517, 297, 519, 520, 521, 522, 523, 524, 2836, -1, + -1, -1, -1, -1, -1, -1, 2882, -1, -1, -1, + -1, -1, 2836, 2889, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2900, -1, -1, -1, -1, -1, + 2906, -1, -1, -1, -1, -1, -1, 2913, 2914, 2915, + 2916, -1, -1, -1, -1, -1, 2656, -1, -1, -1, + -1, 2927, -1, -1, 2930, -1, -1, -1, 2934, 2935, + -1, -1, -1, -1, -1, 2903, -1, -1, 2944, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 2903, + -1, 2691, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2968, -1, -1, 3348, -1, -1, -1, 2975, + 2976, -1, -1, -1, 1718, -1, -1, -1, 2718, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 2072, -1, -1, -1, 2076, -1, -1, 1677, -1, - -1, 2082, -1, -1, -1, 2306, -1, -1, 2309, -1, - 2311, 2312, -1, -1, 3666, -1, -1, -1, -1, -1, - -1, 1579, -1, -1, -1, 2106, -1, 8, -1, -1, - 11, -1, -1, 2334, 15, 16, -1, -1, -1, 20, - 21, 22, -1, -1, -1, -1, -1, 8, 1923, -1, - 11, -1, -1, -1, 15, 16, 37, -1, -1, 20, - 21, 22, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 37, 8, -1, -1, - 11, -1, -1, -1, 15, 16, -1, -1, -1, 20, - 21, 22, -1, -1, 551, -1, -1, -1, -1, 556, - -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, - -1, -1, -1, -1, 1466, 1467, 2417, -1, -1, 1677, - 1472, -1, -1, 2424, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 2434, -1, -1, 2437, 2438, 2439, 2440, - 1819, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2451, -1, 2453, -1, -1, -1, 2457, -1, -1, 2460, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 2441, -1, -1, -1, -1, 2441, -1, - -1, -1, 2057, -1, -1, -1, -1, -1, 2063, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 2503, -1, -1, -1, -1, -1, 2509, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 2523, 2524, -1, 2526, -1, -1, -1, 2497, - 8, -1, -1, 11, 2497, -1, -1, 15, 16, -1, - -1, -1, -1, 224, -1, -1, 1925, -1, -1, -1, - -1, -1, -1, -1, 2555, -1, -1, -1, -1, -1, - -1, 1819, 1017, 224, -1, -1, -1, -1, -1, 47, - -1, -1, 2573, -1, -1, -1, 54, -1, -1, -1, - 2581, 2582, 2583, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 224, 2595, -1, 2597, -1, 2599, -1, - 1979, -1, -1, 81, 2605, -1, -1, -1, -1, -1, - -1, -1, 1991, -1, -1, -1, 297, -1, -1, -1, - -1, -1, -1, 2198, 2625, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 297, -1, -1, 2640, - -1, -1, 2021, 2218, -1, 2613, -1, -1, -1, 2028, - 2613, 2652, -1, -1, 811, 2656, -1, -1, 566, 2234, - 2441, -1, -1, -1, -1, -1, 297, 1925, -1, 147, - 2245, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 2682, 2683, -1, -1, -1, 2261, -1, -1, -1, - 2265, -1, -1, 2072, -1, -1, -1, 2076, -1, -1, - -1, 179, -1, 2082, -1, 2706, -1, -1, -1, -1, - 2678, -1, 2713, 1765, -1, 2678, 2497, -1, 196, 2720, - -1, 1979, -1, 201, -1, -1, -1, 2106, -1, -1, - -1, -1, -1, 1991, -1, 2736, -1, -1, -1, 2740, - -1, 2742, -1, 2744, 2745, -1, -1, 2748, 2749, -1, - -1, 908, 2753, 2754, 2755, -1, 2757, -1, -1, -1, - -1, -1, 240, 2021, -1, -1, -1, -1, -1, -1, - 2028, -1, 1227, -1, -1, -1, -1, 2778, -1, 2780, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 947, -1, -1, -1, 2795, 2796, 2797, 2798, 2799, 2800, - 2801, 2802, 2803, 2804, -1, 962, 963, 964, 965, 966, - -1, -1, -1, -1, 2072, -1, -1, -1, 2076, 297, - -1, 2789, -1, -1, 2082, -1, 2789, -1, -1, 2830, - -1, -1, 2613, -1, 515, 516, 517, 2838, 519, 520, - 521, 522, 523, 524, -1, -1, -1, -1, 2106, -1, - 2851, -1, 760, 761, 515, 516, 517, 1014, 519, 520, - 521, 522, 523, 524, 2832, -1, -1, -1, -1, 2832, - -1, -1, -1, -1, -1, -1, 2877, -1, -1, 2454, - -1, -1, -1, 2884, 515, 516, 517, -1, 519, 520, - 521, 522, 523, 524, 2895, -1, -1, 2678, -1, -1, - 2901, -1, -1, -1, -1, -1, -1, 2908, 2909, 2910, - 2911, -1, 820, -1, -1, -1, -1, -1, -1, -1, - -1, 2922, 400, -1, 2925, -1, -1, -1, 2929, 2930, - 2898, -1, -1, -1, -1, 2898, -1, 2938, -1, -1, - 1992, 1993, 1994, 1995, 1996, 1997, -1, -1, 2000, 2001, - 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, -1, -1, - 2961, -1, -1, -1, -1, -1, -1, 2968, 2969, -1, - -1, -1, -1, 881, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, - 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3001, -1, 3003, -1, -1, -1, -1, -1, 2789, -1, - -1, 1466, 1467, -1, 3015, 2983, -1, 1472, -1, -1, - 2983, 3022, -1, -1, -1, -1, 3027, -1, -1, -1, - -1, -1, 3033, -1, 512, -1, -1, -1, -1, -1, - -1, 519, 520, 521, 522, 523, 524, 3048, -1, -1, - -1, 2832, -1, 3054, 69, 70, -1, -1, -1, -1, - -1, -1, 2441, -1, -1, -1, 3067, 3068, 3069, -1, - -1, -1, -1, -1, 3075, -1, -1, -1, 2653, -1, - 1237, -1, -1, -1, -1, 1242, -1, -1, -1, -1, - -1, 3092, -1, -1, -1, 110, 111, -1, 1255, 114, - 115, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 2688, -1, -1, -1, 2898, 2497, 1276, - -1, -1, 1030, -1, -1, -1, -1, -1, 1036, 3097, - 1038, -1, -1, -1, 3097, -1, -1, -1, -1, 1047, - 2715, 2193, 2194, -1, -1, -1, -1, -1, -1, 1057, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3132, -1, -1, 2742, -1, 3132, - -1, -1, -1, 3174, -1, -1, 191, 192, 3179, -1, - -1, -1, -1, 2441, -1, -1, -1, -1, -1, 1346, - -1, -1, -1, 3194, 1102, -1, -1, 1354, -1, -1, - -1, -1, 2983, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 1127, - 3221, -1, -1, -1, -1, 3226, -1, -1, -1, -1, - 3198, -1, -1, -1, 2613, 3198, 3204, -1, -1, 2497, - -1, 3204, -1, 258, 259, 260, 261, 262, 263, 264, - 265, 3252, -1, 268, 269, -1, 2831, 2309, 3259, 3227, - -1, -1, -1, 1718, 3227, 3266, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 3283, -1, -1, -1, 2861, -1, 1196, 1197, - 2865, -1, -1, -1, -1, -1, -1, -1, -1, 2678, - 2875, -1, -1, 3271, -1, 3306, -1, -1, 3271, -1, - 1765, -1, -1, 3314, -1, -1, 3097, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 343, 344, - -1, -1, -1, -1, 3335, -1, -1, -1, -1, 3340, - 1497, -1, -1, -1, -1, -1, -1, 2922, -1, -1, - -1, 3132, -1, -1, -1, 2613, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3366, -1, -1, -1, 384, - 385, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3387, 3388, -1, -1, - -1, -1, -1, -1, -1, 69, 70, -1, -1, -1, - -1, -1, -1, -1, 3405, -1, 3407, -1, -1, -1, - 2789, 3412, -1, -1, -1, -1, 3384, 3198, -1, -1, - 2678, 3384, -1, 3204, -1, -1, -1, -1, 3003, -1, - 3431, -1, -1, 3434, -1, -1, 110, 111, 3013, -1, - 114, 115, -1, -1, -1, -1, 3227, 3022, -1, -1, - -1, -1, 3453, 2832, 3455, -1, 3457, 3458, -1, 3460, - -1, -1, -1, -1, 3465, -1, -1, -1, -1, 484, - 485, -1, -1, -1, -1, 1383, 1384, -1, 1386, -1, - -1, -1, -1, -1, -1, 3486, -1, -1, -1, 3490, - 3271, -1, -1, 508, 509, -1, -1, -1, -1, -1, - 3501, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 191, 192, 2898, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3531, 2789, -1, -1, -1, -1, -1, 1992, 1993, 1994, - 1995, 1996, 1997, -1, -1, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3570, - -1, -1, -1, -1, 2832, -1, -1, 3578, -1, -1, - 1737, 1489, 1739, -1, 258, 259, 260, 261, 262, 263, - 264, 265, 3593, 1750, 268, 269, 1504, -1, 1506, -1, - -1, 1509, -1, 3384, 2983, -1, 1514, -1, -1, 1517, - -1, 1519, -1, -1, -1, 1523, -1, 1525, -1, 1527, - 3195, -1, 3623, -1, -1, -1, -1, 25, -1, -1, - 2682, 2683, -1, 1790, 3635, 3636, -1, 3638, 3639, -1, - 2898, -1, -1, -1, -1, -1, 3647, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3658, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3242, -1, 343, - 344, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 27, 3684, 82, -1, -1, -1, 33, -1, - 3691, -1, -1, -1, -1, -1, 41, -1, 3666, -1, - 98, -1, -1, 3666, -1, -1, -1, -1, -1, -1, - 384, 385, -1, -1, -1, -1, 61, -1, 3097, -1, - -1, -1, -1, -1, -1, 2983, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3737, -1, 2193, 2194, - -1, 1649, -1, -1, 1901, 1902, 1903, 1904, 1905, 1906, - 148, 3752, -1, 3132, -1, -1, 3757, -1, -1, 3760, - 158, -1, 107, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 171, -1, -1, -1, -1, 176, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 138, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 205, -1, -1, - 484, 485, -1, -1, -1, -1, -1, -1, -1, 3198, - -1, -1, 856, 857, -1, 3204, -1, -1, -1, 3404, - -1, -1, -1, -1, 508, 509, -1, -1, -1, 3097, - -1, -1, -1, 2895, -1, -1, -1, -1, 3227, -1, - -1, 249, -1, -1, 2309, 3430, 254, -1, -1, 204, + -1, -1, 3008, -1, 3010, 2745, -1, -1, -1, -1, + -1, -1, 1383, 1384, -1, 1386, 3022, -1, -1, -1, + -1, 1765, 2990, 3029, -1, -1, -1, -1, 3034, -1, + -1, -1, -1, -1, 3040, -1, 2990, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3055, + -1, -1, -1, -1, -1, 3061, -1, -1, -1, -1, + -1, -1, -1, -1, 1737, -1, 1739, -1, 3074, 3075, + 3076, -1, -1, -1, -1, -1, 3082, 1750, -1, 515, + 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, + -1, -1, -1, 3099, -1, 2835, -1, -1, -1, -1, + -1, -1, 8, -1, -1, 11, -1, -1, -1, 15, + 16, -1, -1, -1, 20, 21, 22, 1790, 1489, -1, + -1, -1, -1, -1, -1, -1, 2866, 3133, -1, -1, + 2870, 3514, 3138, 1504, -1, 1506, 3104, -1, 1509, -1, + 2880, -1, -1, 1514, -1, -1, 1517, 3153, 1519, -1, + 3104, -1, 1523, -1, 1525, -1, 1527, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2922, -1, -1, -1, 3132, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 1792, 3666, -1, 2044, -1, -1, - -1, -1, 3271, -1, -1, -1, -1, -1, 932, -1, - -1, -1, 936, 937, -1, -1, 1814, -1, -1, -1, - 255, -1, 3487, -1, 3489, -1, -1, 1825, -1, 1827, - 2972, 266, 1830, -1, -1, -1, -1, -1, 326, -1, - -1, -1, 1840, 278, 1842, -1, -1, -1, -1, -1, - 3198, -1, -1, 341, -1, -1, 3204, 1855, -1, -1, - -1, -1, 1860, -1, 299, 989, 1864, 1865, 3533, 1867, - -1, 1869, 1870, -1, -1, 310, -1, -1, -1, 3227, - -1, -1, -1, 1007, -1, 3550, -1, -1, 376, 1013, - -1, 379, 1016, -1, -1, 1019, 1020, 1021, 1022, -1, - -1, -1, 390, -1, -1, 393, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3384, -1, -1, -1, -1, - -1, -1, -1, 3271, 359, 413, -1, 3069, 363, -1, - 365, -1, -1, -1, -1, -1, -1, -1, -1, 427, - 1064, 1065, -1, -1, -1, -1, -1, 435, -1, -1, - -1, -1, -1, -1, -1, 390, -1, 445, -1, -1, - 395, -1, 1086, 451, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 411, -1, -1, -1, - -1, -1, 1106, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 480, -1, 1118, 1119, 1120, -1, 1122, 1123, - -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, - 17, 18, -1, 20, 21, 22, -1, -1, 3683, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 37, -1, 2030, -1, 1158, 470, 3384, -1, -1, -1, - 47, -1, -1, -1, 3709, -1, -1, 54, -1, 27, - -1, -1, 1176, 1177, -1, 33, -1, -1, -1, 2057, - -1, -1, -1, 41, -1, 2063, -1, -1, -1, -1, - -1, 2069, -1, -1, 81, -1, -1, 2075, -1, -1, - -1, -1, -1, 61, 3226, -1, -1, -1, -1, 1213, - -1, -1, -1, 1217, 1218, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 1228, 1229, 3, -1, -1, -1, - -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, - 17, 18, -1, 20, 21, 22, -1, -1, -1, 107, - -1, -1, -1, -1, -1, -1, -1, 2682, 2683, -1, - 37, -1, -1, -1, 41, -1, -1, -1, -1, -1, - 47, -1, -1, -1, -1, -1, -1, 54, -1, -1, - 138, 2159, -1, -1, -1, -1, 2164, -1, 1292, -1, - -1, 2169, 179, -1, -1, -1, -1, 2424, -1, 1303, - -1, -1, -1, -1, 81, -1, -1, -1, -1, 196, - -1, 2438, 2439, 2440, 201, -1, -1, 3666, -1, -1, - -1, -1, -1, -1, 1328, -1, 2453, -1, -1, -1, - 2457, -1, -1, 2460, -1, -1, -1, 224, 225, -1, - -1, -1, -1, -1, -1, -1, 204, -1, -1, -1, - -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 2245, -1, -1, - -1, -1, -1, -1, -1, -1, 2503, -1, -1, 2257, - -1, -1, -1, 2261, -1, -1, -1, 2265, -1, -1, - -1, -1, -1, 280, -1, -1, 283, 255, -1, -1, - -1, -1, 179, -1, -1, -1, -1, -1, 266, -1, - 297, -1, 1416, 300, -1, -1, -1, -1, -1, 196, - 278, -1, -1, -1, 201, -1, -1, -1, 2306, -1, - -1, 3453, -1, -1, 2312, -1, -1, -1, 3666, -1, - -1, 299, -1, -1, -1, -1, -1, 224, 225, -1, - -1, -1, 310, -1, 2581, 2582, 2583, -1, -1, -1, - -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, - 2895, -1, -1, -1, -1, 1479, -1, 1481, 1482, -1, + 3186, -1, -1, -1, -1, 3191, -1, 2927, -1, 3157, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1494, 1495, -1, -1, -1, -1, -1, 2922, -1, -1, - -1, 359, -1, 280, -1, 363, 283, 365, -1, -1, - -1, -1, 1516, 400, -1, -1, -1, -1, -1, -1, - 297, -1, -1, 300, -1, -1, -1, -1, -1, -1, - -1, -1, 390, -1, -1, -1, -1, 395, -1, -1, + -1, 3169, -1, 3157, -1, -1, -1, -1, -1, -1, + -1, 3217, -1, -1, -1, 3169, -1, -1, 3224, -1, + -1, -1, -1, -1, 3192, 3231, -1, -1, 1901, 1902, + 1903, 1904, 1905, 1906, -1, -1, -1, -1, 3192, -1, + -1, -1, -1, -1, 3250, -1, -1, -1, 1992, 1993, + 1994, 1995, 1996, 1997, -1, -1, 2000, 2001, 2002, 2003, + 2004, 2005, 2006, 2007, 2008, 2009, -1, 3273, -1, 3237, + 3010, -1, -1, -1, -1, 3281, -1, -1, 1649, -1, + 3020, -1, -1, 3237, -1, -1, -1, -1, -1, 3029, + -1, -1, -1, -1, -1, -1, 3302, 3, -1, -1, + -1, 3307, 8, 3686, -1, 11, -1, -1, -1, 15, + 16, 17, 18, -1, 20, 21, 22, -1, 224, -1, + -1, -1, -1, -1, -1, -1, -1, 3333, -1, -1, + -1, 37, -1, -1, -1, 41, -1, -1, -1, -1, + -1, 47, -1, -1, -1, 3351, 3352, -1, 54, -1, + -1, -1, -1, 27, -1, -1, -1, -1, -1, 33, + -1, -1, -1, 3369, -1, 3371, -1, 41, -1, -1, + 3376, 2044, -1, -1, -1, 81, -1, -1, -1, -1, + 3348, -1, -1, -1, -1, -1, -1, 61, -1, 3395, + 8, 297, 3398, 11, 3348, -1, -1, 15, 16, 17, + 18, -1, 20, 21, 22, -1, -1, -1, -1, -1, + -1, 3417, -1, 3419, 3154, 3421, 3422, -1, 3424, 37, + -1, 1792, -1, -1, 3430, -1, -1, -1, -1, 47, + -1, -1, -1, 107, -1, -1, 54, -1, -1, -1, + -1, -1, -1, 1814, -1, 3451, -1, -1, -1, 3455, + -1, 2195, 2196, -1, 1825, -1, 1827, -1, -1, 1830, + 3466, -1, -1, 81, 138, -1, -1, 3207, -1, 1840, + -1, 1842, -1, 179, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 1855, -1, -1, -1, -1, 1860, + 196, -1, -1, 1864, 1865, 201, 1867, -1, 1869, 1870, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 411, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 224, 225, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 2451, -1, -1, -1, -1, -1, -1, + 204, -1, -1, -1, 240, -1, -1, 3543, -1, -1, + -1, -1, -1, -1, -1, -1, 3514, -1, -1, -1, + -1, 169, -1, -1, -1, -1, 174, -1, -1, -1, + 3514, 179, -1, -1, -1, -1, -1, 2311, -1, -1, + -1, -1, -1, -1, 280, -1, -1, 283, 196, -1, + 3586, 255, -1, 201, -1, -1, -1, -1, 3594, -1, + -1, 297, 266, -1, 300, -1, -1, -1, -1, -1, + -1, -1, -1, 3609, 278, -1, 224, 225, -1, 515, + 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, + -1, -1, 240, -1, -1, 299, -1, -1, 3368, -1, + -1, -1, -1, 3639, -1, -1, 310, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3655, + 3656, -1, 3658, 3659, 3394, -1, -1, -1, -1, 2030, + -1, 3667, 280, -1, -1, 283, -1, -1, -1, -1, + -1, -1, 3678, -1, -1, -1, -1, -1, -1, 297, + -1, -1, 300, -1, -1, 359, 2057, -1, -1, 363, + -1, 365, 2063, -1, 400, -1, -1, -1, 2069, -1, + 3706, -1, -1, -1, 2075, -1, -1, 3713, -1, -1, + -1, -1, 3452, -1, 3454, -1, 390, -1, 3686, -1, + -1, 395, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3686, -1, -1, -1, -1, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2427, -1, 3762, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 2441, 2442, + 2443, 3777, -1, -1, -1, -1, 3782, -1, -1, 3785, + -1, 2454, 400, -1, -1, 2458, -1, -1, 2461, -1, + 2161, -1, -1, -1, -1, 2166, 470, -1, -1, -1, + 2171, -1, -1, -1, -1, 3545, 512, -1, -1, 515, + 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, + -1, -1, -1, -1, -1, -1, 3566, -1, -1, -1, + -1, 2504, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, + 25, 15, 16, 17, 18, -1, 20, 21, 22, 856, + 857, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 37, -1, -1, 2247, 41, -1, -1, + -1, -1, -1, 47, -1, -1, -1, -1, 2259, -1, + 54, -1, 2263, -1, 512, -1, 2267, 515, 516, 517, + -1, 519, 520, 521, 522, 523, 524, 82, -1, 2582, + 2583, 2584, -1, -1, -1, -1, -1, 81, -1, -1, + -1, -1, -1, 98, -1, -1, -1, 0, -1, -1, + -1, -1, -1, -1, -1, 932, -1, 2308, -1, 936, + 937, 2685, 2686, 2314, -1, -1, -1, -1, -1, -1, + 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 33, -1, 35, 36, 3704, -1, -1, -1, -1, -1, + -1, -1, -1, 148, -1, 48, -1, -1, -1, -1, + 53, -1, -1, 158, -1, -1, -1, -1, -1, 62, + -1, 3731, 989, -1, -1, -1, 171, -1, -1, -1, + -1, 176, -1, 76, -1, -1, -1, -1, -1, -1, + 1007, -1, 85, -1, 87, 179, 1013, -1, -1, 1016, + -1, -1, 1019, 1020, 1021, 1022, 99, -1, 101, -1, + 205, -1, 196, -1, -1, -1, -1, 201, -1, 112, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 2736, - -1, -1, 470, -1, -1, -1, -1, 1621, -1, -1, - -1, -1, -1, 400, -1, 512, 1630, -1, 515, 516, - 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, - 1644, -1, -1, -1, 3069, 532, -1, -1, -1, -1, + -1, -1, -1, -1, 127, 128, 129, -1, -1, -1, + 224, 225, -1, -1, -1, 138, 2739, 1064, 1065, -1, + -1, 144, -1, -1, 249, -1, 240, -1, -1, 254, + 153, 2452, 155, 156, -1, -1, -1, -1, -1, 1086, + -1, -1, -1, -1, -1, -1, -1, 170, -1, -1, + -1, 174, -1, -1, -1, -1, -1, -1, -1, 1106, + -1, -1, -1, -1, -1, -1, 280, -1, -1, 283, + -1, 1118, 1119, 1120, -1, 1122, 1123, 200, -1, -1, + -1, -1, -1, 297, -1, -1, 300, -1, -1, -1, + -1, -1, -1, 216, -1, -1, -1, -1, -1, -1, + -1, 326, -1, -1, -1, -1, 2900, -1, -1, -1, + -1, 1158, -1, -1, -1, -1, 341, -1, -1, 2842, + 243, -1, -1, -1, -1, -1, -1, -1, -1, 1176, + 1177, -1, -1, 2927, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1664, -1, -1, -1, -1, -1, -1, -1, 1672, -1, - -1, -1, -1, -1, 1678, 1679, 1680, 1681, 1682, 1683, - 1684, 1685, -1, -1, -1, -1, 1690, 1691, -1, -1, - -1, 1695, -1, -1, -1, 1699, -1, -1, 1702, 1703, - 1704, 1705, 1706, 1707, 1708, 1709, 1710, -1, -1, 1713, - -1, 2838, -1, -1, -1, -1, 1720, 2595, 1722, -1, - -1, 2599, -1, -1, -1, -1, -1, 2605, -1, -1, - -1, -1, -1, -1, -1, 512, 1740, -1, 515, 516, - 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, + -1, 376, -1, -1, 379, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 390, 1213, -1, 393, -1, + 1217, 1218, -1, -1, -1, 2596, -1, -1, -1, 2600, + -1, 1228, 1229, -1, -1, 2606, 400, -1, 413, -1, + 2913, 2914, 2915, 2916, -1, -1, -1, -1, 321, 322, + 323, -1, 427, -1, -1, -1, 329, -1, -1, 332, + 435, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 445, -1, 8, -1, -1, 11, 451, -1, -1, 15, + 16, -1, -1, -1, 2655, -1, -1, -1, 2659, -1, + 363, -1, -1, -1, -1, 1292, -1, -1, -1, 372, + 8, -1, -1, 11, -1, 480, 1303, 15, 16, 17, + 18, 47, 20, 21, 22, 388, -1, -1, 54, -1, + -1, -1, 395, -1, -1, -1, 399, -1, -1, 37, + -1, 1328, 3076, -1, -1, -1, -1, -1, 411, 47, + -1, -1, -1, -1, -1, 81, 54, -1, 512, -1, + 423, 515, 516, 517, 427, 519, 520, 521, 522, 523, + 524, -1, -1, -1, -1, 529, -1, -1, -1, -1, + -1, -1, 2743, 81, -1, 448, 2747, 2748, -1, -1, + -1, 2752, -1, -1, -1, -1, -1, -1, -1, 462, + -1, -1, 465, -1, -1, 468, -1, -1, -1, -1, + 473, -1, -1, -1, -1, -1, -1, -1, -1, 3082, + 2781, 147, -1, -1, -1, -1, -1, 490, -1, 1416, + -1, -1, -1, -1, -1, -1, -1, -1, 2799, 2800, + 2801, 2802, -1, 2804, 2805, 2806, 2807, 2808, -1, -1, + -1, 514, -1, 179, -1, -1, -1, 3191, -1, -1, + -1, -1, -1, -1, -1, 528, -1, -1, 531, -1, + 196, -1, -1, -1, -1, 201, -1, -1, -1, -1, + -1, 179, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 1479, -1, 1481, 1482, -1, -1, 196, -1, + -1, -1, -1, 201, -1, -1, -1, 1494, 1495, -1, + -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 224, 225, -1, 1516, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 240, -1, -1, 2906, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 1776, 1777, 2652, -1, -1, -1, 2656, -1, - -1, 2908, 2909, 2910, 2911, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, + 11, 297, -1, 2934, 15, 16, 17, 18, -1, 20, + 21, 22, 280, -1, -1, 283, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 37, -1, -1, 297, + -1, -1, 300, -1, -1, -1, 47, 2968, -1, -1, + -1, -1, -1, 54, -1, 2976, 8, -1, -1, 11, + -1, -1, -1, 15, 16, 17, 18, -1, 20, 21, + 22, -1, -1, -1, 1621, -1, -1, -1, -1, -1, + 81, -1, -1, 1630, -1, 37, -1, -1, -1, 3010, + -1, -1, -1, -1, -1, 47, -1, 1644, -1, -1, + -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 400, -1, -1, 1664, -1, -1, + -1, -1, -1, 3417, -1, 1672, -1, -1, -1, 81, + -1, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, -1, + -1, -1, 400, 1690, 1691, -1, 3369, -1, 1695, -1, + -1, -1, 1699, -1, 3075, 1702, 1703, 1704, 1705, 1706, + 1707, 1708, 1709, 1710, -1, -1, 1713, -1, -1, -1, + -1, -1, 3395, 1720, -1, 1722, -1, -1, 179, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 3226, -1, -1, -1, 8, -1, -1, 11, -1, - -1, -1, 15, 16, 17, 18, -1, 20, 21, 22, + -1, -1, -1, 1740, -1, 196, -1, -1, -1, -1, + 201, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 37, -1, -1, -1, 41, -1, - -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, - -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 2740, -1, -1, -1, 2744, 2745, -1, -1, - -1, 2749, -1, 1877, -1, -1, -1, -1, 81, -1, - 1884, -1, -1, 1887, 1888, -1, -1, -1, -1, -1, + -1, -1, -1, 224, 225, -1, 512, 179, -1, 1776, + 1777, -1, -1, 519, 520, 521, 522, 523, 524, 240, + -1, -1, -1, 3466, 196, -1, -1, -1, -1, 201, + -1, -1, -1, -1, 512, -1, -1, 515, 516, 517, + -1, 519, 520, 521, 522, 523, 524, -1, -1, -1, + -1, 529, 224, 225, -1, -1, -1, -1, -1, 280, + -1, -1, 283, -1, -1, -1, -1, -1, 240, -1, + -1, -1, -1, -1, -1, -1, 297, -1, -1, 300, + -1, -1, -1, 3224, -1, -1, -1, -1, -1, -1, + 3231, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3543, -1, -1, -1, -1, -1, -1, -1, 280, -1, + 1877, 283, -1, -1, -1, -1, -1, 1884, -1, -1, + 1887, 1888, -1, -1, -1, 297, -1, -1, 300, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, + -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, + -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, + -1, 3302, -1, -1, -1, -1, 3307, -1, 37, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 47, 400, + -1, -1, -1, -1, -1, 54, -1, 1954, 1955, -1, + -1, 8, 3333, -1, 11, -1, 1963, -1, 15, 16, + 17, 18, -1, 20, 21, 22, -1, -1, -1, -1, + 3351, 3352, 81, -1, -1, -1, 1983, 1984, -1, 1986, + 37, -1, -1, -1, -1, -1, -1, -1, 400, -1, + 47, -1, -1, -1, -1, 3376, -1, 54, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 2015, 2016, + -1, -1, 2019, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2778, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 2795, 2796, 2797, - 2798, -1, 2800, 2801, 2802, 2803, 2804, -1, -1, -1, + 3421, -1, -1, 2050, -1, -1, -1, -1, -1, 3430, + -1, 512, 2059, -1, 515, 516, 517, -1, 519, 520, + 521, 522, 523, 524, -1, -1, -1, -1, 529, -1, + 179, 2078, -1, 2080, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 196, -1, -1, + -1, -1, 201, -1, -1, -1, -1, -1, -1, -1, + 512, -1, -1, 515, 516, 517, -1, 519, 520, 521, + 522, 523, 524, -1, 2121, 224, 225, 529, -1, -1, + 2127, -1, 179, -1, -1, -1, -1, -1, 1017, -1, + -1, 240, -1, -1, -1, -1, -1, -1, -1, 196, + -1, -1, -1, 8, 201, -1, 11, -1, -1, -1, + 15, 16, -1, 2160, -1, -1, -1, 2164, -1, -1, + -1, -1, 2169, 2170, -1, -1, -1, 224, 225, -1, + -1, 280, -1, -1, 283, -1, -1, -1, -1, -1, + -1, -1, 47, 240, -1, -1, -1, -1, 297, 54, + -1, 300, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 2216, + -1, -1, 2219, -1, 2221, -1, 81, -1, -1, -1, + -1, -1, -1, 280, -1, -1, 283, -1, -1, -1, + 2237, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 297, -1, -1, 300, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 1143, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 3075, -1, - 1954, 1955, -1, -1, -1, -1, -1, -1, -1, 1963, - 8, -1, -1, 11, -1, -1, -1, 15, 16, 17, - 18, -1, 20, 21, 22, -1, 179, -1, -1, 1983, - 1984, -1, 1986, -1, -1, -1, -1, -1, -1, 37, - -1, -1, -1, 196, -1, -1, -1, -1, 201, 47, + 2277, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 147, -1, -1, -1, -1, 2294, 2295, -1, + -1, 400, -1, -1, -1, -1, -1, 3678, -1, -1, + -1, -1, -1, 1192, -1, -1, 2313, -1, -1, -1, + -1, -1, -1, -1, 179, -1, -1, -1, -1, -1, + 8, 2328, -1, 11, -1, -1, -1, 15, 16, 17, + 18, 196, 20, 21, 22, -1, 201, -1, 1227, -1, + -1, -1, -1, 400, -1, -1, -1, -1, -1, 37, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, - -1, 2015, 2016, -1, -1, 2019, -1, 0, -1, -1, - -1, 224, 225, 2901, -1, -1, -1, -1, 3453, -1, - -1, -1, -1, 81, -1, -1, -1, 240, -1, -1, - 23, -1, -1, -1, -1, -1, 2050, -1, -1, -1, - 33, 2929, 35, 36, -1, 2059, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, - 53, -1, -1, -1, 2078, -1, 2080, 280, -1, 62, - 283, -1, -1, 2961, -1, -1, -1, -1, -1, -1, - -1, 2969, -1, 76, 297, -1, -1, 300, -1, -1, - -1, -1, 85, -1, 87, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 2119, 99, -1, 101, -1, - -1, 2125, -1, -1, -1, 3003, -1, -1, -1, 112, - -1, 179, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 127, 128, 129, -1, 196, -1, - -1, -1, -1, 201, 2158, 138, -1, -1, 2162, -1, - -1, 144, -1, 2167, 2168, -1, -1, -1, -1, -1, - 153, -1, 155, 156, -1, -1, 224, 225, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 170, -1, -1, - 3068, 174, 240, -1, -1, -1, -1, 400, -1, -1, + -1, -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2214, -1, -1, 2217, -1, 2219, -1, 200, -1, -1, + 2397, -1, -1, 81, -1, -1, -1, 1286, -1, 2406, + -1, -1, -1, 512, -1, -1, 515, 516, 517, -1, + 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, + 529, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 297, -1, 8, -1, -1, 11, -1, -1, + -1, 15, 16, 1332, -1, -1, 20, 21, 22, -1, + 1339, -1, -1, -1, -1, 512, -1, -1, 515, 516, + 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, + -1, -1, 529, 47, -1, -1, -1, -1, -1, -1, + 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 179, -1, -1, -1, 2502, -1, -1, -1, -1, + -1, 1390, -1, -1, -1, -1, -1, 81, 196, 8, + -1, -1, 11, 201, -1, -1, 15, 16, 17, 18, + -1, 20, 21, 22, -1, 1414, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 400, 224, 225, 37, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, + -1, -1, 240, -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 2235, 280, 216, -1, 283, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 297, + -1, -1, -1, 1462, -1, 1464, -1, 1466, 1467, -1, + 1469, -1, 81, 1472, -1, -1, 1475, -1, -1, 1478, + -1, -1, 280, -1, 1483, 283, -1, 1486, -1, -1, + -1, -1, -1, -1, -1, 179, -1, -1, -1, 297, -1, -1, 300, -1, -1, -1, -1, -1, -1, -1, - 243, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 2275, -1, -1, -1, -1, -1, -1, 3405, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2292, 2293, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3431, -1, -1, 2311, -1, 512, - -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, - 523, 524, 2326, -1, -1, -1, 529, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 321, 322, - 323, -1, -1, -1, -1, -1, 329, -1, -1, 332, - -1, -1, 400, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 196, -1, -1, -1, 2633, 201, -1, -1, + -1, -1, -1, 2640, 2641, -1, -1, -1, -1, -1, + -1, 1530, -1, -1, -1, -1, -1, 512, -1, 2656, + 224, 225, -1, -1, 519, 520, 521, 522, 523, 524, + -1, -1, 2669, -1, -1, 2672, 240, 2674, -1, -1, + -1, -1, -1, -1, -1, 2682, -1, -1, -1, -1, + 179, -1, -1, 2690, 2691, -1, -1, -1, -1, -1, + 2697, -1, -1, -1, -1, -1, -1, 196, -1, -1, + -1, -1, 201, -1, -1, -1, 280, 2714, -1, 283, + -1, -1, 400, -1, -1, -1, -1, -1, 2725, -1, + -1, -1, -1, 297, -1, 224, 225, -1, 1617, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 2745, -1, + -1, 240, -1, -1, -1, 1634, 3, -1, 5, -1, + -1, -1, -1, -1, -1, -1, 1645, 1646, 1647, -1, + -1, -1, -1, 1652, -1, -1, -1, 1656, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3501, -1, -1, -1, -1, 8, - 363, 3259, 11, -1, -1, -1, 15, 16, 3266, 372, - 2394, 20, 21, 22, -1, -1, -1, -1, -1, 2403, - -1, -1, -1, -1, 3531, 388, -1, -1, 37, -1, - -1, -1, 395, 1017, 69, 70, 399, -1, 47, -1, - -1, -1, -1, -1, -1, 54, -1, -1, 411, -1, + -1, 280, -1, -1, 283, 2792, 2793, -1, -1, -1, + -1, 2798, -1, -1, -1, -1, -1, -1, 297, -1, + -1, 300, -1, -1, -1, 2812, 2813, -1, -1, -1, + -1, -1, 69, 70, -1, -1, -1, -1, 2825, -1, + -1, -1, -1, -1, 512, -1, 400, 515, 516, 517, + 1719, 519, 520, 521, 522, 523, 524, 2844, -1, -1, + -1, 529, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 110, 111, -1, -1, 114, 115, -1, + -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, + 1759, 15, 16, 17, 18, -1, 20, 21, 22, -1, + -1, -1, -1, -1, -1, -1, 1775, -1, -1, -1, + -1, 1780, -1, 37, -1, -1, -1, -1, -1, -1, + -1, 400, -1, 47, -1, -1, -1, -1, 1797, -1, + 54, -1, -1, 2920, 2921, -1, 2923, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 423, -1, -1, -1, 427, -1, -1, -1, -1, -1, - -1, -1, 81, -1, -1, 110, 111, 3335, -1, 114, - 115, -1, 3340, -1, 512, 448, -1, 515, 516, 517, - -1, 519, 520, 521, 522, 523, 524, -1, -1, 462, - -1, 529, 465, -1, -1, 468, -1, -1, 3366, -1, - 473, -1, -1, -1, -1, -1, -1, 2501, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 490, -1, 3387, - 3388, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 191, 192, -1, 81, 512, -1, + -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, + 524, -1, 2959, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 514, -1, -1, 3412, -1, 191, 192, -1, 1143, - -1, -1, -1, -1, -1, 528, -1, -1, 531, -1, - 179, 8, -1, -1, 11, -1, -1, -1, 15, 16, - 17, 18, -1, 20, 21, 22, -1, 196, -1, -1, - -1, -1, 201, -1, -1, -1, -1, -1, -1, 3457, - 37, -1, -1, -1, -1, -1, -1, 3465, 1192, -1, - 47, -1, -1, -1, -1, 224, 225, 54, -1, -1, - -1, -1, -1, 258, 259, 260, 261, 262, 263, 264, - 265, 240, -1, 268, 269, -1, -1, -1, -1, -1, - -1, -1, -1, 1227, 81, -1, 2630, -1, -1, -1, - -1, -1, 8, 2637, 2638, 11, -1, -1, -1, 15, - 16, 17, 18, -1, 20, 21, 22, -1, -1, 2653, - -1, 280, -1, -1, 283, -1, -1, -1, -1, -1, - -1, 37, 2666, -1, -1, 2669, -1, 2671, 297, -1, - -1, 47, -1, -1, -1, 2679, -1, -1, 54, -1, - -1, -1, 1286, 2687, 2688, -1, -1, -1, 343, 344, - 2694, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 81, -1, 2711, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2722, -1, - -1, -1, 179, -1, -1, -1, -1, -1, 1332, 384, - 385, -1, -1, -1, -1, 1339, -1, -1, 2742, 196, - -1, -1, -1, -1, 201, 8, -1, -1, 11, -1, - -1, -1, 15, 16, 17, 18, -1, 20, 21, 22, - -1, -1, -1, -1, -1, -1, -1, 224, 225, -1, - -1, 400, -1, -1, 37, -1, -1, -1, -1, -1, - 3658, -1, -1, 240, 47, -1, 1390, -1, -1, -1, - 2794, 54, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 179, 2808, 2809, -1, -1, -1, -1, - 1414, -1, -1, -1, -1, -1, -1, 2821, 81, -1, - 196, -1, -1, 280, -1, 201, 283, -1, -1, 484, - 485, -1, -1, -1, -1, -1, 2840, -1, -1, -1, - 297, -1, -1, 300, -1, -1, -1, -1, 224, 225, - -1, -1, -1, 508, 509, -1, -1, -1, 1462, -1, - 1464, -1, 1466, 1467, 240, 1469, -1, -1, 1472, -1, - -1, 1475, -1, 528, 1478, -1, -1, -1, -1, 1483, - -1, -1, 1486, 512, -1, -1, 515, 516, 517, -1, + -1, -1, 2979, -1, -1, -1, -1, 2984, 2985, -1, + -1, -1, 2989, -1, -1, -1, -1, 2994, -1, -1, + 2997, 2998, -1, -1, -1, 3002, 3003, -1, -1, 3006, + -1, 258, 259, 260, 261, 262, 263, 264, 265, -1, + -1, 268, 269, 512, -1, 3022, 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, - -1, -1, -1, -1, 280, -1, -1, 283, -1, -1, - -1, 2915, 2916, -1, 2918, -1, 179, -1, -1, -1, - -1, 297, -1, -1, 300, -1, 1530, -1, -1, -1, - -1, -1, -1, 196, -1, -1, -1, -1, 201, -1, - -1, -1, -1, 400, -1, -1, -1, -1, 2952, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 224, 225, -1, -1, -1, -1, -1, 2972, -1, - -1, -1, -1, 2977, 2978, -1, -1, 240, 2982, -1, - -1, -1, -1, 2987, -1, -1, 2990, 2991, -1, -1, - -1, 2995, 2996, -1, -1, 2999, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 3015, -1, 1617, -1, -1, -1, 280, -1, -1, - 283, -1, -1, -1, 400, -1, -1, -1, -1, -1, - 1634, -1, -1, -1, 297, -1, -1, 300, -1, -1, - -1, 1645, 1646, 1647, -1, -1, -1, -1, 1652, -1, - -1, -1, 1656, -1, -1, 512, -1, 3061, 515, 516, - 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, - -1, -1, 529, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3088, -1, -1, -1, -1, -1, + 529, -1, -1, -1, -1, 179, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 196, -1, -1, -1, -1, 201, -1, -1, + -1, 3068, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 1719, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 512, 400, -1, 515, - 516, 517, -1, 519, 520, 521, 522, 523, 524, 8, - -1, -1, 11, 529, -1, 1759, 15, 16, 17, 18, - -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, - -1, 1775, -1, -1, -1, -1, 1780, -1, 37, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, - -1, -1, -1, 1797, -1, 54, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3214, 3215, -1, 3217, -1, -1, -1, -1, -1, -1, - -1, -1, 81, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 3242, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 512, - -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, - 523, 524, 8, -1, -1, 11, 529, -1, -1, 15, - 16, 17, 18, 3277, 20, 21, 22, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3293, - 3294, 37, -1, 3297, -1, 3299, -1, -1, -1, -1, - -1, 47, -1, -1, -1, -1, -1, -1, 54, -1, + 224, 225, -1, -1, -1, -1, 343, 344, 3095, -1, + -1, -1, 1981, -1, -1, -1, 240, -1, -1, -1, + 1989, 1990, -1, 1992, 1993, 1994, 1995, 1996, 1997, -1, + -1, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, + 2009, 2010, -1, -1, -1, -1, -1, 384, 385, -1, + -1, -1, -1, -1, -1, -1, 280, -1, -1, 283, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 179, -1, -1, -1, -1, -1, -1, 3331, -1, -1, - -1, -1, -1, -1, -1, 81, -1, 196, -1, -1, - -1, -1, 201, -1, -1, -1, -1, -1, -1, -1, - -1, 3355, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 224, 225, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1981, -1, -1, - -1, 240, -1, -1, -1, 1989, 1990, -1, 1992, 1993, - 1994, 1995, 1996, 1997, -1, -1, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010, -1, -1, -1, + -1, -1, -1, 297, -1, -1, 300, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 280, -1, -1, 283, -1, -1, -1, -1, -1, - -1, -1, -1, 179, -1, -1, -1, -1, 297, -1, - -1, 300, -1, 3447, -1, -1, -1, 3451, -1, -1, - 196, 3455, -1, -1, -1, 201, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3469, -1, -1, -1, -1, - 3474, 3475, -1, -1, -1, -1, -1, -1, 224, 225, - -1, -1, 3486, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3508, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2122, -1, - -1, -1, 2126, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 280, -1, -1, 283, -1, -1, - -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 297, 3556, 2157, 300, -1, -1, -1, -1, -1, - -1, -1, 3566, -1, -1, -1, -1, 2171, -1, -1, - -1, -1, 2176, -1, 3578, -1, 2180, 2181, 2182, 2183, - 2184, 2185, 2186, 2187, -1, -1, -1, -1, -1, 2193, - 2194, 3595, 2196, 2197, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 2210, -1, -1, 2213, - 3614, -1, -1, -1, -1, -1, -1, 2221, 2222, 2223, - 2224, 2225, 2226, 2227, 2228, 2229, 2230, -1, -1, -1, + -1, -1, 3179, 3180, -1, 3182, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 2256, 512, 400, -1, 515, 516, 517, -1, - 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, - 529, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, - 17, 18, -1, 20, 21, 22, -1, -1, -1, -1, - -1, 3705, 3706, 3707, -1, 2309, -1, -1, -1, -1, - 37, -1, 3716, -1, -1, -1, -1, -1, -1, -1, - 47, -1, -1, -1, -1, -1, -1, 54, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3741, -1, -1, + 3207, -1, -1, 8, -1, -1, 11, -1, -1, -1, + 15, 16, 17, 18, -1, 20, 21, 22, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 484, 485, -1, + -1, -1, 37, -1, -1, 2124, -1, 3244, -1, 2128, + -1, -1, 47, -1, -1, -1, -1, -1, -1, 54, + -1, 508, 509, 3260, 3261, -1, 400, 3264, -1, 3266, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 81, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 512, -1, -1, 515, - 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, - -1, -1, -1, 529, -1, -1, -1, -1, -1, -1, - -1, 2395, -1, -1, -1, -1, 3800, -1, -1, -1, - -1, -1, 2406, 2407, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, - 11, -1, -1, -1, 15, 16, 17, 18, -1, 20, - 21, 22, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, - -1, -1, 179, -1, -1, -1, 47, -1, -1, -1, - -1, -1, -1, 54, -1, -1, -1, -1, -1, 196, - -1, -1, -1, -1, 201, -1, -1, -1, -1, -1, + 2159, -1, -1, -1, -1, -1, 81, -1, -1, -1, + -1, -1, -1, -1, 2173, -1, -1, -1, -1, 2178, + -1, 3298, -1, 2182, 2183, 2184, 2185, 2186, 2187, 2188, + 2189, -1, -1, -1, -1, -1, 2195, 2196, -1, 2198, + 2199, -1, -1, -1, -1, 3322, -1, -1, -1, -1, + -1, -1, -1, 2212, -1, -1, 2215, -1, -1, -1, + -1, -1, -1, -1, 2223, 2224, 2225, 2226, 2227, 2228, + 2229, 2230, 2231, 2232, 8, -1, -1, 11, -1, -1, + -1, 15, 16, -1, -1, -1, 20, 21, 22, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 512, 2258, + -1, 515, 516, 517, 179, 519, 520, 521, 522, 523, + 524, -1, -1, 47, -1, 529, -1, -1, -1, -1, + 54, 196, -1, -1, -1, -1, 201, -1, -1, -1, + -1, -1, -1, -1, 3411, -1, -1, -1, 3415, -1, + -1, -1, 3419, -1, -1, -1, -1, 81, -1, 224, + 225, -1, 2311, -1, -1, -1, -1, 3434, -1, -1, + -1, -1, 3439, 3440, -1, 240, -1, -1, -1, -1, + -1, -1, -1, -1, 3451, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 81, -1, -1, -1, -1, -1, -1, 224, 225, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2512, -1, - 2514, -1, -1, 240, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 2530, 2531, 2532, -1, - -1, 2535, 2536, 2537, 2538, 2539, 2540, -1, -1, -1, - 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, - -1, -1, -1, 280, 2558, 2559, 283, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3473, -1, -1, -1, + -1, -1, -1, -1, -1, 280, -1, -1, 283, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 297, -1, -1, 300, -1, -1, -1, -1, -1, -1, - 2584, -1, -1, -1, 8, -1, -1, 11, 179, -1, - 2594, 15, 16, 17, 18, -1, 20, 21, 22, -1, - -1, -1, -1, -1, -1, 196, -1, -1, -1, -1, - 201, -1, -1, 37, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 47, -1, 2629, -1, -1, -1, -1, - 54, -1, 2636, 224, 225, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 2648, -1, -1, -1, -1, 240, - 2654, -1, -1, -1, -1, 2659, 2660, 81, -1, -1, - -1, -1, -1, 2667, 2668, -1, -1, -1, -1, -1, - -1, -1, -1, 400, -1, -1, -1, 2681, 2682, 2683, - 2684, -1, 2686, -1, -1, -1, 2690, -1, -1, 280, - 8, -1, 283, 11, -1, -1, -1, 15, 16, 17, - 18, -1, 20, 21, 22, -1, 297, -1, -1, 300, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, - -1, -1, -1, -1, -1, 8, -1, -1, 11, 47, - -1, -1, 15, 16, 17, 18, 54, 20, 21, 22, - -1, -1, -1, -1, -1, -1, 2750, -1, -1, -1, - -1, -1, -1, -1, 37, 179, -1, -1, -1, -1, - -1, -1, -1, 81, 47, -1, -1, -1, -1, -1, - -1, 54, 196, -1, -1, -1, -1, 201, -1, -1, - -1, -1, -1, -1, -1, 512, -1, -1, 515, 516, - 517, -1, 519, 520, 521, 522, 523, 524, 81, -1, - 224, 225, 529, -1, -1, -1, -1, -1, -1, 400, - -1, -1, -1, -1, -1, -1, 240, -1, -1, -1, + -1, -1, 297, -1, -1, 300, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 2398, + -1, -1, -1, -1, -1, 179, 8, -1, -1, 11, + 2409, 2410, -1, 15, 16, 17, 18, -1, 20, 21, + 22, -1, 196, -1, -1, -1, -1, 201, -1, -1, + -1, -1, -1, -1, -1, 37, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 47, -1, -1, -1, -1, + 224, 225, 54, -1, -1, 3572, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 3582, 240, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 3594, -1, 81, + -1, -1, -1, -1, -1, 400, -1, -1, -1, -1, + -1, -1, -1, -1, 3611, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 283, + -1, -1, -1, 3630, 2513, -1, 2515, -1, -1, -1, + -1, -1, -1, 297, -1, -1, -1, -1, -1, -1, + -1, -1, 2531, 2532, 2533, -1, -1, 2536, 2537, 2538, + 2539, 2540, 2541, -1, -1, -1, 2545, 2546, 2547, 2548, + 2549, 2550, 2551, 2552, 2553, 2554, -1, -1, -1, -1, + 2559, 2560, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, + -1, -1, -1, -1, -1, -1, 2585, -1, -1, -1, + -1, -1, -1, -1, 196, -1, 2595, 512, -1, 201, + 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, + 3727, 3728, 3729, -1, 529, -1, -1, -1, -1, -1, + -1, 3738, 224, 225, -1, -1, 400, -1, -1, -1, + -1, -1, -1, 2632, -1, -1, -1, -1, 240, -1, + 2639, -1, -1, -1, -1, -1, -1, -1, -1, 3766, + -1, -1, 2651, -1, -1, -1, -1, -1, 2657, -1, + -1, -1, -1, 2662, 2663, -1, -1, -1, -1, -1, + -1, 2670, 2671, -1, -1, -1, -1, -1, 280, -1, + -1, 283, -1, -1, -1, 2684, 2685, 2686, 2687, -1, + 2689, -1, -1, -1, 2693, 297, -1, -1, 300, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3826, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, - 17, 18, -1, 20, 21, 22, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 280, -1, -1, 283, - 37, 179, -1, -1, -1, -1, -1, -1, -1, -1, - 47, -1, 2876, 297, -1, -1, 300, 54, 196, -1, - -1, -1, -1, 201, -1, -1, -1, -1, -1, -1, - -1, 2895, -1, -1, -1, -1, 179, -1, -1, -1, - -1, -1, -1, -1, 81, -1, 224, 225, -1, -1, - -1, -1, -1, 196, -1, -1, -1, -1, 201, -1, - -1, 512, 240, -1, 515, 516, 517, -1, 519, 520, - 521, 522, 523, 524, -1, -1, -1, -1, 529, -1, - -1, 224, 225, -1, -1, -1, -1, -1, -1, 2953, - -1, 2955, -1, -1, -1, -1, -1, 240, -1, -1, - 2964, -1, 280, -1, -1, 283, -1, -1, -1, -1, - -1, -1, 2976, -1, -1, 2979, 400, 2981, -1, 297, - -1, 2985, 300, -1, 2988, 2989, -1, -1, 2992, 2993, - -1, -1, -1, -1, -1, -1, 3000, 280, -1, -1, - 283, -1, 179, -1, -1, -1, -1, -1, -1, -1, - 3014, -1, -1, -1, 297, -1, -1, 300, -1, 196, - -1, -1, -1, -1, 201, -1, 3030, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, - 11, -1, -1, -1, 15, 16, -1, 224, 225, 20, - 21, 22, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 240, -1, 3069, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 47, -1, -1, -1, - -1, -1, 400, 54, -1, -1, -1, -1, 512, -1, + -1, -1, -1, 8, -1, -1, 11, -1, -1, -1, + 15, 16, 17, 18, -1, 20, 21, 22, 512, -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, - 524, -1, -1, 280, -1, 529, 283, -1, -1, -1, - 81, -1, -1, -1, -1, -1, -1, 400, -1, -1, - 297, -1, -1, 300, -1, -1, -1, -1, -1, -1, + 524, -1, 37, -1, 2753, -1, -1, -1, -1, -1, + -1, -1, 47, -1, -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, -1, 20, 21, 22, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 81, -1, 400, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1, -1, - -1, 3175, -1, 47, -1, -1, -1, -1, -1, -1, - 54, -1, -1, -1, -1, 3189, -1, -1, -1, -1, - -1, -1, -1, -1, 512, -1, -1, 515, 516, 517, - -1, 519, 520, 521, 522, 523, 524, 81, 179, -1, - -1, 529, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 3225, 3226, 400, -1, 196, -1, -1, -1, 512, - 201, -1, 515, 516, 517, -1, 519, 520, 521, 522, - 523, 524, -1, -1, 527, -1, 3250, 3251, -1, -1, - 3254, -1, -1, 224, 225, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 240, - -1, 3275, -1, -1, -1, -1, -1, -1, -1, -1, - 3284, -1, -1, 3287, 3288, 3289, -1, -1, 3292, -1, - -1, 3295, 3296, -1, -1, -1, -1, -1, -1, -1, - 3304, -1, -1, -1, -1, 179, -1, -1, -1, -1, - -1, -1, 283, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 196, -1, -1, -1, 297, 201, -1, -1, - -1, -1, -1, -1, -1, 512, -1, -1, 515, 516, - 517, -1, 519, 520, 521, 522, 523, 524, 3352, -1, - 224, 225, 529, -1, 3358, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 240, 3371, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 280, -1, -1, 283, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 297, 3428, 3429, 300, -1, -1, 400, - -1, 3435, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3471, 3472, 3473, + -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, + 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, + -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, + -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, + -1, -1, 2881, -1, -1, -1, -1, -1, 37, -1, + -1, -1, -1, -1, 179, -1, -1, -1, 47, -1, + -1, 2900, -1, -1, -1, 54, -1, -1, -1, -1, + 512, 196, -1, 515, 516, 517, 201, 519, 520, 521, + 522, 523, 524, -1, -1, -1, -1, 529, -1, -1, + -1, -1, 81, -1, -1, -1, -1, -1, -1, 224, + 225, -1, -1, -1, -1, 179, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 240, -1, -1, -1, -1, + -1, 2960, 196, 2962, -1, -1, -1, 201, -1, -1, + -1, -1, 2971, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2983, -1, -1, 2986, -1, 2988, + 224, 225, -1, 2992, -1, 280, 2995, 2996, 283, -1, + 2999, 3000, -1, -1, -1, -1, 240, -1, 3007, -1, + -1, -1, 297, -1, -1, 300, -1, -1, -1, -1, + -1, -1, 3021, -1, -1, -1, -1, -1, -1, -1, + 179, -1, -1, -1, -1, -1, -1, -1, 3037, -1, + -1, -1, -1, -1, -1, -1, 280, 196, -1, 283, + -1, -1, 201, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 297, -1, -1, 300, -1, -1, -1, + -1, -1, -1, -1, -1, 224, 225, 3076, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 3497, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3509, -1, -1, -1, -1, + -1, 240, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3108, + 3109, -1, -1, -1, -1, 400, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, + -1, 280, 11, -1, 283, 3134, 15, 16, 17, 18, + -1, 20, 21, 22, -1, -1, -1, -1, 297, 3148, + -1, 300, -1, -1, -1, -1, -1, -1, 37, -1, + -1, -1, -1, -1, -1, -1, 400, -1, 47, -1, + -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 400, -1, -1, -1, + -1, 3190, 3191, -1, -1, -1, -1, -1, -1, -1, + -1, 25, 81, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3215, 3216, -1, -1, + 3219, -1, -1, -1, -1, -1, -1, 512, -1, -1, + 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, + -1, -1, -1, 3242, 529, -1, -1, -1, -1, -1, + -1, 400, 3251, -1, -1, 3254, 3255, 3256, 82, -1, + 3259, -1, -1, 3262, 3263, 69, 70, -1, -1, -1, + -1, -1, 3271, -1, 98, -1, -1, -1, 512, -1, + -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, + 524, -1, -1, -1, -1, 529, -1, -1, -1, -1, + 179, -1, -1, -1, -1, -1, 110, 111, -1, -1, + 114, 115, -1, -1, -1, -1, -1, 196, -1, -1, + 3319, -1, 201, -1, 148, -1, 3325, -1, -1, -1, + -1, -1, -1, -1, 158, -1, -1, -1, -1, 3338, + -1, -1, -1, -1, -1, 224, 225, 171, -1, -1, + -1, -1, 176, -1, -1, -1, -1, -1, -1, -1, + -1, 240, -1, 512, -1, -1, 515, 516, 517, -1, + 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, + 529, 205, -1, -1, -1, -1, -1, 191, 192, -1, + -1, -1, -1, 3392, 3393, -1, -1, -1, -1, -1, + 3399, 280, -1, -1, 283, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 297, -1, + -1, 300, -1, -1, -1, 249, -1, -1, -1, -1, + 254, -1, -1, -1, -1, -1, -1, 3436, 3437, 3438, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 512, -1, -1, 515, 516, 517, -1, 519, 520, - 521, 522, 523, 524, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3571, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3581, -1, -1, + -1, -1, -1, -1, 258, 259, 260, 261, 262, 263, + 264, 265, -1, 3462, 268, 269, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 3474, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 320, -1, -1, -1, + -1, -1, 326, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 341, -1, -1, + -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 343, + 344, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 376, -1, -1, 379, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 390, -1, -1, 393, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3609, -1, -1, -1, -1, + 384, 385, -1, -1, -1, -1, -1, -1, 3587, 413, + -1, -1, -1, -1, -1, -1, -1, -1, 3597, -1, + -1, -1, -1, 427, -1, -1, -1, -1, -1, -1, + 434, 435, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 445, -1, -1, -1, -1, 3625, 451, -1, -1, + -1, -1, -1, 512, -1, -1, 515, 516, 517, -1, + 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, + 529, -1, -1, -1, -1, 3654, 480, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3634, -1, -1, -1, -1, -1, -1, -1, 512, -1, - -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, - 524, -1, -1, -1, -1, 529, -1, 3661, -1, -1, + 484, 485, 3681, -1, -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3681, -1, -1, + -1, -1, 3701, -1, 508, 509, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, - 33, 34, -1, -1, -1, -1, -1, 40, -1, -1, + 33, 34, -1, -1, 528, -1, -1, 40, -1, -1, 43, 44, 45, -1, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, -1, -1, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, 78, 79, 80, -1, 82, - 3744, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 3755, 95, 96, 97, 98, 99, 100, -1, 102, + 3769, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 3780, 95, 96, 97, 98, 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, -1, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, @@ -16763,11 +16837,11 @@ static const yytype_int16 yycheck[] = 225, -1, 280, -1, -1, 283, -1, -1, -1, -1, -1, -1, -1, 196, -1, 240, -1, -1, 201, 297, 280, -1, 300, 283, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 297, -1, -1, + -1, -1, 69, 70, -1, -1, -1, 297, -1, -1, 300, 224, 225, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 280, -1, 240, 283, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 400, - -1, -1, 297, -1, -1, 300, -1, -1, -1, -1, + -1, -1, 297, 110, 111, 300, -1, 114, 115, -1, -1, -1, -1, -1, -1, -1, -1, 400, -1, -1, -1, -1, -1, -1, -1, 8, -1, 280, 11, -1, 283, -1, 15, 16, 17, 18, -1, 20, 21, 22, @@ -16775,172 +16849,100 @@ static const yytype_int16 yycheck[] = -1, -1, 400, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, 400, 54, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 191, 192, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, -1, -1, -1, -1, 400, -1, -1, -1, -1, -1, 512, -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, 529, 512, -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, 529, 400, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 512, -1, -1, 515, 516, 517, + -1, 258, 259, 260, 261, 262, 263, 264, 265, -1, + -1, 268, 269, -1, 512, -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, 529, 512, -1, -1, 515, 516, 517, -1, 519, - 520, 521, 522, 523, 524, -1, 179, -1, -1, 529, + 520, 521, 522, 523, 524, -1, 179, 527, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 196, -1, -1, -1, 512, 201, -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, - -1, -1, -1, -1, 529, -1, 8, -1, -1, 11, - -1, 224, 225, 15, 16, 17, 18, -1, 20, 21, - 22, -1, -1, -1, -1, -1, -1, 240, -1, 512, - -1, -1, 515, 516, 517, 37, 519, 520, 521, 522, - 523, 524, -1, -1, 527, 47, -1, -1, -1, -1, - -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 527, -1, -1, -1, 343, 344, -1, -1, + -1, 224, 225, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 240, -1, 512, + -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, + 523, 524, -1, -1, 527, -1, -1, 384, 385, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 280, -1, -1, - 283, -1, -1, -1, -1, -1, -1, -1, -1, 81, + 283, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 297, -1, -1, 300, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 484, 485, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, + -1, 508, 509, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 400, -1, -1, - -1, -1, -1, -1, 196, -1, -1, -1, -1, 201, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 224, 225, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 240, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 280, -1, - -1, 283, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 297, -1, -1, 300, 512, - -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, - 523, 524, -1, -1, 527, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 400, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, - 512, -1, -1, 515, 516, 517, -1, 519, 520, 521, - 522, 523, 524, -1, -1, 527, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, - 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, - 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, - 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, - 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, - 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, - 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, - 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, - 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, - 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, - -1, -1, -1, -1, 521, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, - 28, 29, 30, -1, 32, 33, 34, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, - 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, - 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, - 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, - 78, 79, 80, -1, -1, -1, 84, 85, 86, 87, - 88, 89, -1, 91, 92, 93, -1, 95, 96, 97, - 98, 99, 100, -1, -1, 103, 104, 105, 106, 107, + -1, -1, -1, -1, -1, 3, -1, -1, -1, 512, + -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, + 523, 524, -1, -1, 527, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, - -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, - 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, - 148, -1, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, -1, 163, -1, 165, 166, 167, - 168, -1, 170, -1, 172, -1, -1, -1, 176, 177, - 178, -1, 180, 181, 182, -1, 184, 185, 186, 187, - -1, 189, 190, 191, 192, 193, 194, 195, -1, 197, - 198, 199, 200, -1, 202, 203, 204, 205, 206, 207, - 208, -1, 210, -1, 212, 213, 214, 215, 216, 217, - 218, 219, -1, 221, -1, 223, -1, -1, 226, -1, - 228, 229, 230, -1, 232, 233, 234, -1, -1, 237, - -1, 239, -1, -1, 242, 243, 244, 245, 246, 247, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, + 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, -1, 275, 276, 277, - 278, 279, -1, 281, 282, -1, 284, -1, 286, 287, - 288, 289, 290, 291, -1, 293, 294, -1, -1, 297, - 298, 299, -1, -1, 302, 303, 304, -1, 306, -1, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, -1, -1, -1, -1, 325, 326, 327, - -1, 329, 330, 331, 332, 333, 334, -1, 336, 337, - 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, - 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, - 358, 359, 360, 361, 362, 363, 364, 365, 366, -1, - 368, 369, -1, 371, 372, 373, 374, 375, 376, 377, + 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, - -1, -1, 390, 391, 392, 393, 394, 395, 396, 397, - 398, -1, -1, 401, 402, 403, 404, -1, 406, 407, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 421, 422, -1, -1, 425, 426, -1, - 428, -1, 430, 431, 432, 433, 434, 435, -1, 437, - 438, 439, -1, -1, 442, 443, 444, 445, 446, -1, - 448, 449, 450, 451, 452, 453, 454, 455, -1, -1, - 458, 459, 460, -1, -1, 463, 464, 465, 466, -1, - 468, 469, 470, 471, 472, 473, 474, 475, -1, 477, - -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, - 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, + 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, + 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, + 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, + 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, 521, -1, -1, -1, -1, -1, -1, @@ -16993,262 +16995,520 @@ static const yytype_int16 yycheck[] = 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 3, 4, 5, -1, -1, -1, 9, + 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, 521, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, - 30, -1, 32, 33, 34, -1, -1, -1, 38, -1, - -1, -1, -1, 43, 44, 45, -1, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, -1, - 60, 61, 62, 63, 64, 65, -1, -1, 68, 69, + 30, -1, 32, 33, 34, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 44, 45, -1, -1, 48, 49, + -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, + -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, 78, 79, - 80, -1, 82, -1, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, -1, 95, 96, 97, 98, 99, - 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, + 80, -1, -1, -1, 84, 85, 86, 87, 88, 89, + -1, 91, 92, 93, -1, 95, 96, 97, 98, 99, + 100, -1, -1, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, 148, -1, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, -1, 165, 166, 167, 168, -1, - 170, -1, 172, 173, -1, 175, 176, 177, 178, 179, + 160, 161, -1, 163, -1, 165, 166, 167, 168, -1, + 170, -1, 172, -1, -1, -1, 176, 177, 178, -1, 180, 181, 182, -1, 184, 185, 186, 187, -1, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 190, 191, 192, 193, 194, 195, -1, 197, 198, 199, 200, -1, 202, 203, 204, 205, 206, 207, 208, -1, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - -1, 221, -1, 223, 224, 225, 226, 227, 228, 229, - 230, -1, 232, 233, 234, -1, -1, 237, 238, 239, - 240, -1, 242, 243, 244, 245, 246, 247, 248, 249, + 210, -1, 212, 213, 214, 215, 216, 217, 218, 219, + -1, 221, -1, 223, -1, -1, 226, -1, 228, 229, + 230, -1, 232, 233, 234, -1, -1, 237, -1, 239, + -1, -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - -1, 281, 282, 283, 284, -1, 286, 287, 288, 289, - 290, 291, -1, 293, 294, 295, -1, 297, 298, 299, - -1, -1, 302, 303, 304, 305, 306, 307, 308, 309, + 270, 271, 272, 273, -1, 275, 276, 277, 278, 279, + -1, 281, 282, -1, 284, -1, 286, 287, 288, 289, + 290, 291, -1, 293, 294, -1, -1, 297, 298, 299, + -1, -1, 302, 303, 304, -1, 306, -1, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, -1, -1, -1, -1, 325, 326, 327, 328, 329, + 320, -1, -1, -1, -1, 325, 326, 327, -1, 329, 330, 331, 332, 333, 334, -1, 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, -1, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, 382, 383, 384, 385, 386, 387, -1, 389, + -1, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 387, -1, -1, 390, 391, 392, 393, 394, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, -1, 406, 407, 408, 409, + -1, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 421, 422, -1, -1, 425, 426, -1, 428, 429, + 420, 421, 422, -1, -1, 425, 426, -1, 428, -1, 430, 431, 432, 433, 434, 435, -1, 437, 438, 439, - -1, -1, 442, 443, 444, 445, 446, 447, 448, 449, + -1, -1, 442, 443, 444, 445, 446, -1, 448, 449, 450, 451, 452, 453, 454, 455, -1, -1, 458, 459, - 460, 461, -1, 463, 464, 465, 466, -1, 468, 469, - 470, 471, 472, 473, 474, 475, -1, 477, 478, 479, + 460, -1, -1, 463, 464, 465, 466, -1, 468, 469, + 470, 471, 472, 473, 474, 475, -1, 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, -1, -1, 8, -1, -1, 11, -1, 519, - 520, 15, 16, 17, 18, -1, 20, 21, 22, -1, - -1, -1, 8, -1, -1, 11, -1, -1, -1, 15, - 16, 17, 18, 37, 20, 21, 22, -1, 42, -1, + 510, 511, 3, 4, 5, -1, -1, -1, 9, -1, + -1, 521, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, + -1, 32, 33, 34, -1, -1, -1, 38, -1, -1, + -1, -1, 43, 44, 45, -1, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, -1, 60, + 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, + 71, 72, 73, 74, -1, 76, 77, 78, 79, 80, + -1, 82, -1, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, -1, 95, 96, 97, 98, 99, 100, + -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, + 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, + 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, + 141, 142, 143, -1, 145, 146, 147, 148, -1, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, -1, 165, 166, 167, 168, -1, 170, + -1, 172, 173, -1, 175, 176, 177, 178, 179, 180, + 181, 182, -1, 184, 185, 186, 187, -1, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + -1, 202, 203, 204, 205, 206, 207, 208, -1, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, -1, + 221, -1, 223, 224, 225, 226, 227, 228, 229, 230, + -1, 232, 233, 234, -1, -1, 237, 238, 239, 240, + -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, + 281, 282, 283, 284, -1, 286, 287, 288, 289, 290, + 291, -1, 293, 294, 295, -1, 297, 298, 299, -1, + -1, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + -1, -1, -1, -1, 325, 326, 327, 328, 329, 330, + 331, 332, 333, 334, -1, 336, 337, 338, 339, 340, + 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, + 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, + 361, 362, 363, 364, 365, 366, -1, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, 382, 383, 384, 385, 386, 387, -1, 389, 390, + 391, 392, 393, 394, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 421, 422, -1, -1, 425, 426, -1, 428, 429, 430, + 431, 432, 433, 434, 435, -1, 437, 438, 439, -1, + -1, 442, 443, 444, 445, 446, 447, 448, 449, 450, + 451, 452, 453, 454, 455, -1, -1, 458, 459, 460, + 461, -1, 463, 464, 465, 466, -1, 468, 469, 470, + 471, 472, 473, 474, 475, -1, 477, 478, 479, 480, + 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, -1, -1, 8, -1, -1, 11, -1, 519, 520, + 15, 16, 17, 18, -1, 20, 21, 22, -1, -1, + -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, + 17, 18, 37, 20, 21, 22, -1, 42, -1, -1, + -1, -1, 47, -1, -1, -1, -1, -1, -1, 54, + 37, -1, -1, -1, -1, -1, 8, -1, -1, 11, + 47, -1, -1, 15, 16, 17, 18, 54, 20, 21, + 22, -1, -1, -1, 8, -1, 81, 11, -1, -1, + -1, 15, 16, 17, 18, 37, 20, 21, 22, 41, + -1, -1, -1, -1, 81, 47, -1, -1, -1, -1, + -1, -1, 54, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, - 54, 37, -1, -1, -1, -1, -1, 8, -1, -1, - 11, 47, -1, -1, 15, 16, 17, 18, 54, 20, - 21, 22, -1, -1, -1, 8, -1, 81, 11, -1, - -1, -1, 15, 16, 17, 18, 37, 20, 21, 22, - -1, -1, -1, -1, -1, 81, 47, -1, -1, -1, - -1, -1, -1, 54, 37, -1, -1, -1, 41, -1, - -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, - -1, 54, -1, 127, -1, -1, -1, -1, -1, -1, - 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, - -1, -1, 8, -1, -1, 11, -1, -1, -1, 15, - 16, 17, 18, -1, 20, 21, 22, -1, -1, -1, - -1, -1, -1, -1, -1, 179, -1, -1, -1, -1, - -1, 37, -1, 169, -1, -1, -1, -1, 174, -1, - -1, 47, 196, 179, -1, -1, -1, 201, 54, -1, + 54, -1, 127, -1, -1, -1, -1, -1, -1, 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 196, -1, -1, -1, -1, 201, -1, 168, -1, -1, - 224, 225, -1, -1, -1, 81, -1, -1, 179, -1, - -1, -1, -1, -1, -1, -1, 240, -1, 224, 225, - -1, -1, -1, -1, -1, 196, 179, -1, -1, -1, - 201, -1, -1, -1, 240, -1, -1, -1, -1, -1, - -1, -1, -1, 196, -1, -1, -1, -1, 201, -1, - -1, -1, -1, 224, 225, -1, 280, -1, -1, 283, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 240, - -1, 224, 225, 297, 280, -1, 300, 283, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 240, -1, -1, - -1, 297, -1, -1, 300, -1, -1, -1, -1, -1, - -1, -1, -1, 179, -1, -1, -1, -1, -1, 280, - -1, -1, 283, -1, -1, -1, -1, -1, -1, -1, - 196, -1, -1, -1, -1, 201, 297, 280, -1, 300, - 283, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 297, -1, -1, 300, 224, 225, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 330, - -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 400, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, - -1, -1, 11, -1, 400, -1, 15, 16, 17, 18, - -1, 20, 21, 22, 280, -1, -1, 283, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, - -1, 297, 41, -1, 300, -1, -1, -1, 47, 400, - -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, - -1, -1, -1, 467, -1, -1, -1, 400, 324, -1, + -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, + -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, + 17, 18, -1, 20, 21, 22, -1, -1, -1, -1, + -1, -1, -1, -1, 179, -1, -1, -1, -1, -1, + 37, 168, -1, -1, 41, -1, -1, -1, -1, -1, + 47, 196, 179, -1, -1, -1, 201, 54, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 196, + -1, -1, -1, -1, 201, -1, -1, -1, -1, 224, + 225, -1, -1, -1, 81, -1, -1, 179, -1, -1, + -1, -1, -1, -1, -1, 240, -1, 224, 225, -1, + -1, -1, -1, -1, 196, 179, -1, -1, -1, 201, + -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, + -1, -1, 196, -1, -1, -1, -1, 201, -1, -1, + -1, -1, 224, 225, -1, 280, -1, -1, 283, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 240, -1, + 224, 225, 297, 280, -1, 300, 283, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 240, -1, -1, -1, + 297, -1, -1, 300, -1, -1, -1, -1, -1, -1, + -1, -1, 179, -1, -1, -1, -1, -1, 280, -1, + -1, 283, -1, -1, -1, -1, -1, -1, -1, 196, + -1, -1, -1, 330, 201, 297, 280, -1, 300, 283, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 81, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 297, -1, -1, 300, 224, 225, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 512, -1, - -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, - 524, -1, -1, -1, -1, -1, 512, -1, -1, 515, - 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, - -1, -1, -1, -1, 400, -1, 8, -1, -1, 11, - -1, -1, -1, 15, 16, 17, 18, -1, 20, 21, - 22, 512, -1, -1, 515, 516, 517, -1, 519, 520, - 521, 522, 523, 524, -1, 37, -1, -1, -1, 512, - 179, -1, 515, 516, 517, 47, 519, 520, 521, 522, - 523, 524, 54, -1, -1, -1, -1, 196, 8, -1, - -1, 11, 201, -1, -1, 15, 16, 17, 18, -1, - 20, 21, 22, -1, -1, -1, -1, -1, -1, 81, - -1, -1, -1, -1, -1, 224, 225, 37, -1, -1, - -1, 41, -1, -1, -1, -1, -1, 47, -1, -1, - -1, 240, -1, -1, 54, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 512, -1, -1, 515, - 516, 517, -1, 519, 520, 521, 522, 523, 524, -1, - -1, 81, -1, -1, -1, -1, -1, -1, -1, 8, - -1, 280, 11, -1, 283, -1, 15, 16, 17, 18, - -1, 20, 21, 22, -1, -1, -1, -1, 297, -1, - -1, 300, -1, -1, -1, -1, -1, -1, 37, -1, - -1, -1, 174, -1, -1, -1, -1, 179, 47, -1, - -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, - -1, -1, -1, -1, 196, -1, -1, -1, -1, 201, + -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, + 324, -1, -1, -1, -1, 400, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, + -1, 11, -1, 400, -1, 15, 16, 17, 18, -1, + 20, 21, 22, 280, -1, -1, 283, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 37, -1, -1, + 297, -1, -1, 300, -1, -1, -1, 47, 400, -1, + -1, -1, -1, -1, 54, -1, -1, -1, -1, -1, + -1, -1, 467, -1, -1, -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 81, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 224, 225, -1, -1, -1, -1, -1, 179, - -1, -1, -1, -1, -1, -1, -1, -1, 240, -1, - -1, -1, -1, -1, -1, -1, 196, -1, -1, -1, - -1, 201, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 224, 225, -1, -1, 280, -1, - -1, 283, -1, -1, -1, -1, -1, -1, -1, -1, - 240, -1, -1, -1, -1, 297, -1, -1, 300, -1, - 169, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 179, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 196, -1, -1, - 280, -1, 201, 283, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 297, -1, -1, - 300, -1, -1, -1, -1, 224, 225, -1, -1, -1, + -1, 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 240, -1, 512, -1, -1, 515, 516, 517, -1, - 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, - -1, -1, -1, 8, -1, -1, 11, -1, 400, -1, - 15, 16, 17, 18, 19, 20, 21, 22, -1, -1, - -1, 280, -1, -1, 283, -1, -1, -1, -1, -1, - -1, -1, 37, -1, -1, -1, -1, -1, 297, -1, - -1, 300, 47, -1, -1, -1, -1, -1, -1, 54, + -1, -1, -1, -1, -1, -1, -1, 512, -1, -1, + 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, + -1, -1, -1, -1, -1, 512, -1, -1, 515, 516, + 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, + -1, -1, -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 400, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 81, -1, -1, -1, - 8, -1, -1, 11, -1, -1, -1, 15, 16, 17, - 18, -1, 20, 21, 22, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, - 512, -1, -1, 515, 516, 517, 54, 519, 520, 521, - 522, 523, 524, -1, -1, -1, -1, -1, -1, -1, - -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 81, -1, -1, -1, -1, -1, -1, + 512, -1, -1, 515, 516, 517, -1, 519, 520, 521, + 522, 523, 524, -1, 174, -1, -1, -1, 512, 179, + -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, + 524, -1, -1, -1, -1, -1, 196, 8, -1, -1, + 11, 201, -1, -1, 15, 16, 17, 18, -1, 20, + 21, 22, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 224, 225, 37, -1, -1, -1, + 41, -1, -1, -1, -1, -1, 47, -1, -1, -1, + 240, -1, -1, 54, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 512, -1, -1, 515, 516, + 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, + 81, -1, -1, -1, -1, -1, -1, -1, 8, -1, + 280, 11, -1, 283, -1, 15, 16, 17, 18, -1, + 20, 21, 22, -1, -1, -1, -1, 297, -1, -1, + 300, -1, -1, -1, -1, -1, -1, 37, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 47, -1, -1, + -1, -1, -1, -1, 54, 8, -1, -1, 11, -1, + -1, -1, 15, 16, 17, 18, 19, 20, 21, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 512, -1, 179, 515, 516, 517, -1, 519, - 520, 521, 522, 523, 524, -1, -1, -1, -1, -1, - -1, 196, -1, -1, 8, -1, 201, 11, -1, -1, - -1, 15, 16, 17, 18, -1, 20, 21, 22, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 224, - 225, -1, -1, 37, -1, -1, -1, 41, -1, -1, - -1, -1, -1, 47, -1, 240, -1, -1, -1, -1, - 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 179, -1, 512, -1, -1, 515, 516, 517, -1, - 519, 520, 521, 522, 523, 524, -1, 81, 196, -1, - -1, -1, -1, 201, 8, 280, -1, 11, 283, -1, - -1, 15, 16, 17, 18, -1, 20, 21, 22, -1, - -1, -1, 297, -1, -1, 300, 224, 225, -1, -1, - -1, -1, -1, 37, -1, -1, -1, -1, -1, -1, - -1, -1, 240, 47, -1, -1, -1, -1, -1, -1, - 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 81, -1, -1, 37, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 47, -1, -1, -1, 179, -1, + -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 196, -1, -1, -1, -1, + 201, -1, -1, -1, -1, -1, -1, -1, 81, -1, + 400, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 224, 225, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 240, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 169, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, - -1, -1, 280, -1, -1, 283, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 179, -1, -1, -1, 297, - -1, -1, 300, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 196, -1, -1, -1, -1, 201, -1, -1, - -1, -1, -1, -1, -1, 400, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 196, -1, -1, 280, + -1, 201, 283, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 297, -1, -1, 300, + -1, -1, -1, -1, 224, 225, 179, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 224, 225, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 240, -1, -1, -1, + 240, -1, 512, 196, -1, 515, 516, 517, 201, 519, + 520, 521, 522, 523, 524, -1, 8, -1, -1, 11, + -1, -1, -1, 15, 16, 17, 18, -1, 20, 21, + 22, 224, 225, -1, -1, -1, -1, -1, -1, -1, + 280, -1, -1, 283, -1, 37, -1, 240, -1, -1, + -1, -1, -1, -1, -1, 47, -1, 297, -1, -1, + 300, -1, 54, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 400, + -1, -1, -1, -1, -1, 8, -1, 280, 11, 81, + 283, -1, 15, 16, 17, 18, -1, 20, 21, 22, + -1, -1, -1, -1, 297, -1, -1, 300, -1, -1, + -1, -1, -1, -1, 37, -1, -1, -1, 41, -1, + -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, + -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 179, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, + 400, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 196, -1, -1, -1, 280, 201, -1, 283, - -1, -1, 400, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 297, -1, -1, 300, -1, -1, -1, - 224, 225, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 240, 512, 436, -1, - 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, - -1, -1, -1, -1, -1, 8, -1, -1, 11, -1, - -1, -1, 15, 16, 17, 18, -1, 20, 21, 22, - -1, -1, -1, -1, -1, -1, 280, -1, -1, 283, - -1, -1, -1, -1, 37, -1, -1, -1, -1, -1, - -1, -1, -1, 297, 47, -1, 300, -1, -1, -1, - -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 512, -1, 400, 515, 516, 517, - -1, 519, 520, 521, 522, 523, 524, -1, 81, -1, + -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, + -1, 512, -1, -1, 515, 516, 517, -1, 519, 520, + 521, 522, 523, 524, 196, -1, -1, 400, -1, 201, -1, -1, -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, -1, 20, 21, 22, -1, -1, + -1, -1, 224, 225, -1, -1, -1, -1, -1, -1, + -1, -1, 37, -1, -1, -1, -1, -1, 240, -1, + -1, -1, 47, -1, -1, -1, 179, -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 37, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 47, -1, -1, -1, -1, -1, -1, 54, + -1, -1, 512, 196, -1, 515, 516, 517, 201, 519, + 520, 521, 522, 523, 524, -1, 81, -1, 280, -1, + -1, 283, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 224, 225, -1, -1, 297, -1, -1, 300, -1, + -1, -1, -1, -1, -1, -1, -1, 240, -1, 512, + -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, + 523, 524, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 400, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 81, -1, -1, -1, + -1, 8, -1, -1, 11, -1, -1, 280, 15, 16, + 283, -1, -1, 20, 21, 22, -1, -1, -1, -1, + -1, -1, -1, -1, 297, -1, -1, 300, -1, -1, + 37, -1, -1, -1, 179, -1, 8, -1, -1, 11, + 47, -1, -1, 15, 16, 17, 18, 54, 20, 21, + 22, 196, -1, -1, -1, -1, 201, -1, 400, -1, + -1, -1, -1, -1, -1, 37, -1, -1, -1, -1, + -1, -1, -1, -1, 81, 47, -1, -1, -1, 224, + 225, -1, 54, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 436, 240, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, + 8, -1, -1, 11, -1, -1, -1, 15, 16, 17, + 18, -1, 20, 21, 22, -1, -1, 400, -1, -1, + -1, -1, -1, -1, -1, 280, -1, -1, 283, 37, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, + -1, -1, 297, -1, -1, 300, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 179, -1, 512, -1, - -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, - 524, -1, -1, 196, -1, -1, -1, -1, 201, -1, + 512, -1, 179, 515, 516, 517, -1, 519, 520, 521, + 522, 523, 524, 81, -1, -1, -1, -1, -1, 196, + -1, -1, -1, -1, 201, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 224, 225, -1, + -1, -1, -1, -1, 196, -1, -1, -1, -1, 201, + -1, -1, -1, 240, -1, -1, -1, -1, -1, 512, + -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, + 523, 524, 224, 225, -1, 400, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 240, -1, + -1, -1, -1, 280, -1, -1, 283, -1, -1, -1, + -1, 179, -1, -1, -1, -1, -1, -1, -1, -1, + 297, -1, -1, 300, -1, -1, -1, -1, 196, -1, + -1, -1, -1, 201, -1, -1, -1, 8, 280, -1, + 11, 283, -1, -1, 15, 16, -1, -1, -1, 20, + 21, 22, -1, -1, -1, 297, 224, 225, 300, -1, + -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, + -1, -1, 240, -1, -1, -1, 47, -1, -1, -1, + -1, -1, -1, 54, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 512, -1, -1, + 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, + 81, -1, 280, -1, -1, 283, -1, -1, -1, -1, + -1, -1, -1, 400, -1, -1, -1, -1, -1, 297, + -1, -1, 300, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 224, 225, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 179, -1, -1, -1, 512, -1, - -1, 515, 516, 517, -1, 519, 520, 521, 522, 523, - 524, 196, -1, -1, -1, -1, 201, 280, -1, -1, - 283, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 297, -1, -1, 300, -1, 224, - 225, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 280, -1, -1, 283, -1, + -1, -1, -1, -1, -1, 196, -1, -1, -1, -1, + 201, -1, 400, -1, -1, 512, -1, -1, 515, 516, + 517, -1, 519, 520, 521, 522, 523, 524, -1, -1, + -1, -1, -1, 224, 225, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 240, + 512, -1, -1, 515, 516, 517, -1, 519, 520, 521, + 522, 523, 524, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 297, -1, -1, 300, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 280, + -1, -1, 283, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 297, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 400, -1, -1, + -1, -1, -1, -1, 512, -1, -1, 515, 516, 517, + -1, 519, 520, 521, 522, 523, 524, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 512, - -1, -1, 515, 516, 517, -1, 519, 520, 521, 522, - 523, 524, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3, -1, 5, -1, -1, -1, -1, 512, -1, -1, - 515, 516, 517, -1, 519, 520, 521, 522, 523, 524, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 3, -1, 5, -1, -1, -1, + -1, 512, -1, -1, 515, 516, 517, -1, 519, 520, + 521, 522, 523, 524, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, + 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, + 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, + 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 3, -1, 5, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, + 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, + 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, + 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, + 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, + 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, + 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, + 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, + 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, + 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, + 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, + 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, + 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, + 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, + 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, + 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, + 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, + 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, @@ -17351,464 +17611,464 @@ static const yytype_int16 yycheck[] = 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, + 35, 36, -1, 38, -1, -1, -1, -1, 43, 44, + 45, -1, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, -1, 60, 61, 62, 63, 64, + 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, + -1, 76, 77, 78, 79, 80, -1, 82, -1, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, -1, + 95, 96, 97, 98, 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, - 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, - 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, - 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, + 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, + 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, + 145, 146, 147, 148, -1, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, -1, 163, -1, + 165, 166, 167, 168, -1, 170, -1, 172, 173, -1, + 175, 176, 177, 178, 179, 180, 181, 182, -1, 184, + 185, 186, 187, -1, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, -1, 202, 203, 204, + 205, 206, 207, 208, -1, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, -1, 221, -1, 223, 224, + 225, 226, 227, 228, 229, 230, -1, 232, 233, 234, + -1, -1, 237, 238, 239, 240, -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 275, 276, 277, 278, 279, -1, 281, 282, 283, 284, + -1, 286, 287, 288, 289, 290, 291, -1, 293, 294, + -1, -1, 297, 298, 299, -1, -1, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 315, 316, 317, 318, 319, 320, -1, -1, -1, -1, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + -1, 336, 337, 338, 339, 340, 341, -1, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 365, 366, -1, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, - 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, - 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, - 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, + 385, 386, 387, -1, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, + -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 421, 422, -1, -1, + 425, 426, -1, 428, 429, 430, 431, 432, 433, 434, + 435, -1, 437, 438, 439, -1, -1, 442, 443, 444, + 445, 446, -1, 448, 449, 450, 451, 452, 453, 454, + 455, -1, -1, 458, 459, 460, 461, -1, 463, 464, + 465, 466, -1, 468, 469, 470, 471, 472, 473, 474, + 475, -1, 477, 478, 479, 480, 481, 482, 483, 484, + 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, + -1, -1, -1, -1, -1, -1, -1, 43, 44, 45, + -1, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, -1, -1, 61, 62, 63, 64, 65, + -1, 67, 68, 69, 70, 71, 72, 73, 74, -1, + 76, 77, 78, 79, 80, -1, 82, -1, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, -1, 95, + 96, 97, 98, 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, + 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, + 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, + 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, + 146, 147, 148, -1, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, -1, 163, -1, 165, + 166, 167, 168, -1, 170, -1, 172, 173, -1, 175, + 176, 177, 178, 179, 180, 181, 182, -1, 184, 185, + 186, 187, -1, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, 199, 200, -1, 202, 203, 204, 205, + 206, 207, 208, -1, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, -1, 221, -1, 223, 224, 225, + 226, 227, 228, 229, 230, -1, 232, 233, 234, -1, + -1, 237, 238, 239, 240, -1, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, -1, 281, 282, 283, 284, -1, + 286, 287, 288, 289, 290, 291, -1, 293, 294, -1, + -1, 297, 298, 299, -1, -1, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, -1, -1, -1, -1, 325, + 326, 327, 328, 329, 330, 331, 332, 333, 334, -1, + 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, + 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, + 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, + 366, -1, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, -1, -1, 390, 391, 392, 393, 394, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, - 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, - 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, - 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 416, 417, 418, 419, 420, 421, 422, -1, -1, 425, + 426, -1, 428, 429, 430, 431, 432, 433, 434, 435, + -1, 437, 438, 439, -1, -1, 442, 443, 444, 445, + 446, -1, 448, 449, 450, 451, 452, 453, 454, 455, + -1, -1, 458, 459, 460, -1, -1, 463, 464, 465, + 466, -1, 468, 469, 470, 471, 472, 473, 474, 475, + -1, 477, 478, 479, 480, 481, 482, 483, 484, 485, + -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 27, 28, 29, 30, -1, 32, 33, 34, -1, -1, + -1, -1, -1, -1, -1, -1, 43, 44, 45, -1, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, + -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, + 77, 78, 79, 80, -1, 82, -1, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, -1, 95, 96, + 97, 98, 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, + -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, + 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, + 147, 148, -1, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, -1, 163, -1, 165, 166, + 167, 168, -1, 170, -1, 172, 173, -1, 175, 176, + 177, 178, 179, 180, 181, 182, -1, 184, 185, 186, + 187, -1, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, -1, 202, 203, 204, 205, 206, + 207, 208, -1, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, -1, 221, -1, 223, 224, 225, 226, + 227, 228, 229, 230, -1, 232, 233, 234, -1, -1, + 237, 238, 239, 240, -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, - 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 277, 278, 279, -1, 281, 282, 283, 284, -1, 286, + 287, 288, 289, 290, 291, -1, 293, 294, -1, -1, + 297, 298, 299, -1, -1, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, - 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, - 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 317, 318, 319, 320, -1, -1, -1, -1, 325, 326, + 327, 328, 329, 330, 331, 332, 333, 334, -1, 336, + 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, + 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, - 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + -1, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, - 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, + 387, -1, -1, 390, 391, 392, 393, 394, 395, 396, + 397, 398, -1, 400, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, - 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, - 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, - 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, - 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 417, 418, 419, 420, 421, 422, -1, -1, 425, 426, + -1, 428, 429, 430, 431, 432, 433, 434, 435, -1, + 437, 438, 439, -1, -1, 442, 443, 444, 445, 446, + -1, 448, 449, 450, 451, 452, 453, 454, 455, -1, + -1, 458, 459, 460, -1, -1, 463, 464, 465, 466, + -1, 468, 469, 470, 471, 472, 473, 474, 475, -1, + 477, 478, 479, 480, 481, 482, 483, 484, 485, -1, + -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, - 28, 29, 30, -1, 32, 33, 34, 35, 36, -1, - 38, -1, -1, -1, -1, 43, 44, 45, -1, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, -1, 60, 61, 62, 63, 64, 65, -1, -1, - 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, - 78, 79, 80, -1, 82, -1, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, -1, 95, 96, 97, - 98, 99, 100, -1, 102, 103, 104, 105, 106, 107, + 28, 29, 30, -1, 32, 33, 34, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, + 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, + 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, -1, -1, 83, 84, 85, 86, 87, + 88, 89, -1, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, -1, -1, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, 148, -1, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, -1, 165, 166, 167, - 168, -1, 170, -1, 172, 173, -1, 175, 176, 177, - 178, 179, 180, 181, 182, -1, 184, 185, 186, 187, - -1, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 168, -1, 170, 171, 172, -1, -1, -1, 176, 177, + 178, -1, 180, 181, 182, -1, 184, 185, 186, 187, + -1, 189, 190, 191, 192, 193, 194, 195, -1, 197, 198, 199, 200, -1, 202, 203, 204, 205, 206, 207, - 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 219, -1, 221, -1, 223, 224, 225, 226, 227, + 208, -1, 210, -1, 212, 213, 214, 215, 216, 217, + 218, 219, -1, 221, -1, 223, -1, -1, 226, -1, 228, 229, 230, -1, 232, 233, 234, -1, -1, 237, - 238, 239, 240, -1, 242, 243, 244, 245, 246, 247, + -1, 239, -1, -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, - 278, 279, -1, 281, 282, 283, 284, -1, 286, 287, + 268, 269, 270, 271, 272, 273, -1, 275, 276, 277, + 278, 279, -1, 281, 282, -1, 284, -1, 286, 287, 288, 289, 290, 291, -1, 293, 294, -1, -1, 297, - 298, 299, -1, -1, 302, 303, 304, 305, 306, 307, + 298, 299, -1, -1, 302, 303, 304, -1, 306, -1, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, -1, -1, -1, -1, 325, 326, 327, - 328, 329, 330, 331, 332, 333, 334, -1, 336, 337, + -1, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, -1, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 368, 369, -1, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, - -1, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, -1, 400, 401, 402, 403, 404, -1, 406, 407, + -1, -1, 390, 391, 392, 393, 394, 395, 396, 397, + 398, -1, -1, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, -1, -1, 425, 426, -1, - 428, 429, 430, 431, 432, 433, 434, 435, -1, 437, + 428, -1, 430, 431, 432, 433, 434, 435, -1, 437, 438, 439, -1, -1, 442, 443, 444, 445, 446, -1, - 448, 449, 450, 451, 452, 453, 454, 455, -1, -1, - 458, 459, 460, 461, -1, 463, 464, 465, 466, -1, + 448, 449, 450, 451, 452, 453, 454, 455, -1, 457, + 458, 459, 460, -1, -1, 463, 464, 465, 466, -1, 468, 469, 470, 471, 472, 473, 474, 475, -1, 477, - 478, 479, 480, 481, 482, 483, 484, 485, -1, -1, + -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, -1, -1, -1, - -1, -1, -1, -1, 43, 44, 45, -1, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - -1, -1, 61, 62, 63, 64, 65, -1, 67, 68, - 69, 70, 71, 72, 73, 74, -1, 76, 77, 78, - 79, 80, -1, 82, -1, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, -1, 95, 96, 97, 98, - 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, + -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, + 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, + -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, -1, -1, -1, 84, 85, 86, 87, 88, + 89, -1, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, -1, -1, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, 148, -1, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, -1, 165, 166, 167, 168, - -1, 170, -1, 172, 173, -1, 175, 176, 177, 178, - 179, 180, 181, 182, -1, 184, 185, 186, 187, -1, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 170, 171, 172, -1, -1, -1, 176, 177, 178, + -1, 180, 181, 182, -1, 184, 185, 186, 187, -1, + 189, 190, 191, 192, 193, 194, 195, -1, 197, 198, 199, 200, -1, 202, 203, 204, 205, 206, 207, 208, - -1, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, -1, 221, -1, 223, 224, 225, 226, 227, 228, - 229, 230, -1, 232, 233, 234, -1, -1, 237, 238, + -1, 210, -1, 212, 213, 214, 215, 216, 217, 218, + 219, -1, 221, -1, 223, -1, -1, 226, -1, 228, + 229, 230, -1, 232, 233, 234, -1, -1, 237, -1, 239, 240, -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, -1, 281, 282, 283, 284, -1, 286, 287, 288, + 269, 270, 271, 272, 273, -1, 275, 276, 277, 278, + 279, -1, 281, 282, -1, 284, -1, 286, 287, 288, 289, 290, 291, -1, 293, 294, -1, -1, 297, 298, - 299, -1, -1, 302, 303, 304, 305, 306, 307, 308, + 299, -1, -1, 302, 303, 304, -1, 306, -1, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, -1, -1, -1, -1, 325, 326, 327, 328, - 329, 330, 331, 332, 333, 334, -1, 336, 337, 338, + 319, 320, -1, -1, -1, -1, 325, 326, 327, -1, + 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, -1, 368, - 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 369, -1, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, -1, -1, 390, 391, 392, 393, 394, 395, 396, 397, 398, - -1, 400, 401, 402, 403, 404, -1, 406, 407, 408, + -1, -1, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, -1, -1, 425, 426, -1, 428, - 429, 430, 431, 432, 433, 434, 435, -1, 437, 438, + -1, 430, 431, 432, 433, 434, 435, -1, 437, 438, 439, -1, -1, 442, 443, 444, 445, 446, -1, 448, - 449, 450, 451, 452, 453, 454, 455, -1, -1, 458, + 449, 450, 451, 452, 453, 454, 455, -1, 457, 458, 459, 460, -1, -1, 463, 464, 465, 466, -1, 468, - 469, 470, 471, 472, 473, 474, 475, -1, 477, 478, + 469, 470, 471, 472, 473, 474, 475, -1, 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, - 30, -1, 32, 33, 34, -1, -1, -1, -1, -1, - -1, -1, -1, 43, 44, 45, -1, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, -1, - -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, + 30, -1, 32, 33, 34, -1, -1, -1, 38, -1, + -1, 41, -1, 43, 44, 45, -1, 47, 48, 49, + 50, 51, 52, 53, -1, 55, 56, 57, 58, -1, + 60, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, 78, 79, - 80, -1, 82, -1, 84, 85, 86, 87, 88, 89, + -1, -1, 82, -1, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, -1, 95, 96, 97, 98, 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, 148, -1, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, -1, 163, -1, 165, 166, 167, 168, -1, + 150, 151, 152, 153, -1, 155, 156, 157, 158, 159, + 160, -1, -1, 163, -1, 165, 166, 167, 168, -1, 170, -1, 172, 173, -1, 175, 176, 177, 178, 179, - 180, 181, 182, -1, 184, 185, 186, 187, -1, 189, + 180, 181, 182, -1, -1, -1, 186, 187, -1, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, -1, 202, 203, 204, 205, 206, 207, 208, -1, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 210, 211, -1, 213, 214, 215, 216, 217, 218, 219, -1, 221, -1, 223, 224, 225, 226, 227, 228, 229, 230, -1, 232, 233, 234, -1, -1, 237, 238, 239, 240, -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - -1, 281, 282, 283, 284, -1, 286, 287, 288, 289, + 270, 271, 272, 273, 274, 275, 276, 277, 278, -1, + -1, 281, 282, 283, 284, -1, -1, 287, 288, 289, 290, 291, -1, 293, 294, -1, -1, 297, 298, 299, - -1, -1, 302, 303, 304, 305, 306, 307, 308, 309, + -1, -1, 302, 303, -1, 305, 306, 307, -1, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, -1, -1, -1, -1, 325, 326, 327, 328, 329, - 330, 331, 332, 333, 334, -1, 336, 337, 338, 339, + 320, -1, -1, -1, -1, 325, 326, -1, 328, 329, + 330, -1, 332, 333, 334, -1, 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, -1, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, 382, 383, 384, 385, 386, 387, -1, -1, + 380, 381, 382, 383, 384, 385, 386, 387, -1, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 421, 422, -1, -1, 425, 426, -1, 428, 429, + 420, 421, -1, -1, -1, 425, 426, -1, 428, 429, 430, 431, 432, 433, 434, 435, -1, 437, 438, 439, - -1, -1, 442, 443, 444, 445, 446, -1, 448, 449, - 450, 451, 452, 453, 454, 455, -1, -1, 458, 459, - 460, -1, -1, 463, 464, 465, 466, -1, 468, 469, - 470, 471, 472, 473, 474, 475, -1, 477, 478, 479, + -1, -1, 442, 443, -1, 445, -1, -1, 448, 449, + 450, 451, 452, 453, 454, 455, 456, -1, 458, 459, + 460, 461, -1, 463, 464, 465, 466, -1, 468, 469, + 470, 471, 472, -1, 474, 475, -1, 477, 478, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, - -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, + -1, 491, 492, 493, 494, 495, 496, 3, -1, 5, + -1, -1, -1, -1, -1, -1, -1, -1, 508, 509, + 510, 511, -1, -1, -1, -1, -1, 23, 24, 25, + 26, 27, 28, 29, 30, -1, 32, 33, 34, 35, + 36, -1, -1, -1, -1, -1, -1, -1, 44, 45, + -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, + -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, + -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, + 76, 77, 78, 79, 80, -1, -1, -1, 84, 85, + 86, 87, 88, 89, -1, 91, 92, 93, -1, 95, + 96, 97, 98, 99, 100, -1, -1, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, + 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, + 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, + 146, 147, 148, -1, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, -1, 163, -1, 165, + 166, 167, 168, -1, 170, -1, 172, -1, -1, -1, + 176, 177, 178, -1, 180, 181, 182, -1, 184, 185, + 186, 187, -1, 189, 190, 191, 192, 193, 194, 195, + -1, 197, 198, 199, 200, -1, 202, 203, 204, 205, + 206, 207, 208, -1, 210, -1, 212, 213, 214, 215, + 216, 217, 218, 219, -1, 221, -1, 223, -1, -1, + 226, -1, 228, 229, 230, -1, 232, 233, 234, -1, + -1, 237, -1, 239, -1, -1, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, -1, 275, + 276, 277, 278, 279, -1, 281, 282, -1, 284, -1, + 286, 287, 288, 289, 290, 291, -1, 293, 294, -1, + -1, 297, 298, 299, -1, -1, 302, 303, 304, -1, + 306, -1, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, -1, -1, -1, -1, 325, + 326, 327, -1, 329, 330, 331, 332, 333, 334, -1, + 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, + 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, + 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, + 366, -1, 368, 369, -1, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, -1, -1, 390, 391, 392, 393, 394, 395, + 396, 397, 398, -1, -1, 401, 402, 403, 404, -1, + 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 421, 422, -1, -1, 425, + 426, -1, 428, -1, 430, 431, 432, 433, 434, 435, + -1, 437, 438, 439, -1, -1, 442, 443, 444, 445, + 446, -1, 448, 449, 450, 451, 452, 453, 454, 455, + -1, -1, 458, 459, 460, -1, -1, 463, 464, 465, + 466, -1, 468, 469, 470, 471, 472, 473, 474, 475, + -1, 477, -1, 479, 480, 481, 482, 483, 484, 485, + -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, - -1, 32, 33, 34, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, - 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, - 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, - 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - -1, -1, 83, 84, 85, 86, 87, 88, 89, -1, - 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - -1, -1, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, - 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, - 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, - 141, 142, 143, -1, 145, 146, 147, 148, -1, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, -1, 165, 166, 167, 168, -1, 170, - 171, 172, -1, -1, -1, 176, 177, 178, -1, 180, - 181, 182, -1, 184, 185, 186, 187, -1, 189, 190, - 191, 192, 193, 194, 195, -1, 197, 198, 199, 200, - -1, 202, 203, 204, 205, 206, 207, 208, -1, 210, - -1, 212, 213, 214, 215, 216, 217, 218, 219, -1, - 221, -1, 223, -1, -1, 226, -1, 228, 229, 230, - -1, 232, 233, 234, -1, -1, 237, -1, 239, -1, - -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, 273, -1, 275, 276, 277, 278, 279, -1, - 281, 282, -1, 284, -1, 286, 287, 288, 289, 290, - 291, -1, 293, 294, -1, -1, 297, 298, 299, -1, - -1, 302, 303, 304, -1, 306, -1, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - -1, -1, -1, -1, 325, 326, 327, -1, 329, 330, - 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, - 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, - 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, 366, -1, 368, 369, -1, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385, 386, 387, -1, -1, 390, - 391, 392, 393, 394, 395, 396, 397, 398, -1, -1, - 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 421, 422, -1, -1, 425, 426, -1, 428, -1, 430, - 431, 432, 433, 434, 435, -1, 437, 438, 439, -1, - -1, 442, 443, 444, 445, 446, -1, 448, 449, 450, - 451, 452, 453, 454, 455, -1, 457, 458, 459, 460, - -1, -1, 463, 464, 465, 466, -1, 468, 469, 470, - 471, 472, 473, 474, 475, -1, 477, -1, 479, 480, - 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 44, 45, -1, + -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, + 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, + -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, + 77, 78, 79, 80, -1, -1, -1, 84, 85, 86, + 87, 88, 89, -1, 91, 92, 93, -1, 95, 96, + 97, 98, 99, 100, -1, -1, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, + -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, + 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, + 147, 148, -1, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, -1, 163, -1, 165, 166, + 167, 168, -1, 170, -1, 172, -1, -1, -1, 176, + 177, 178, -1, 180, 181, 182, -1, 184, 185, 186, + 187, -1, 189, 190, 191, 192, 193, 194, 195, -1, + 197, 198, 199, 200, -1, 202, 203, 204, 205, 206, + 207, 208, -1, 210, -1, 212, 213, 214, 215, 216, + 217, 218, 219, -1, 221, -1, 223, -1, -1, 226, + -1, 228, 229, 230, -1, 232, 233, 234, -1, -1, + 237, -1, 239, -1, -1, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, -1, 275, 276, + 277, 278, 279, -1, 281, 282, -1, 284, -1, 286, + 287, 288, 289, 290, 291, -1, 293, 294, -1, -1, + 297, 298, 299, -1, -1, 302, 303, 304, -1, 306, + -1, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, -1, -1, -1, -1, 325, 326, + 327, -1, 329, 330, 331, 332, 333, 334, -1, 336, + 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, + 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, + -1, 368, 369, -1, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, + 387, -1, -1, 390, 391, 392, 393, 394, 395, 396, + 397, 398, -1, -1, 401, 402, 403, 404, -1, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, -1, -1, 425, 426, + -1, 428, -1, 430, 431, 432, 433, 434, 435, -1, + 437, 438, 439, -1, -1, 442, 443, 444, 445, 446, + -1, 448, 449, 450, 451, 452, 453, 454, 455, -1, + -1, 458, 459, 460, -1, -1, 463, 464, 465, 466, + -1, 468, 469, 470, 471, 472, 473, 474, 475, -1, + 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, + -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, - 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, - 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, - 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, -1, - -1, -1, 84, 85, 86, 87, 88, 89, -1, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, -1, - -1, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, - 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, - 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, - 142, 143, -1, 145, 146, 147, 148, -1, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - -1, 163, -1, 165, 166, 167, 168, -1, 170, 171, - 172, -1, -1, -1, 176, 177, 178, -1, 180, 181, - 182, -1, 184, 185, 186, 187, -1, 189, 190, 191, - 192, 193, 194, 195, -1, 197, 198, 199, 200, -1, - 202, 203, 204, 205, 206, 207, 208, -1, 210, -1, - 212, 213, 214, 215, 216, 217, 218, 219, -1, 221, - -1, 223, -1, -1, 226, -1, 228, 229, 230, -1, - 232, 233, 234, -1, -1, 237, -1, 239, 240, -1, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, -1, 275, 276, 277, 278, 279, -1, 281, - 282, -1, 284, -1, 286, 287, 288, 289, 290, 291, - -1, 293, 294, -1, -1, 297, 298, 299, -1, -1, - 302, 303, 304, -1, 306, -1, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, -1, - -1, -1, -1, 325, 326, 327, -1, 329, 330, 331, - 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, - -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, - 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, - 362, 363, 364, 365, 366, -1, 368, 369, -1, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, -1, -1, 390, 391, - 392, 393, 394, 395, 396, 397, 398, -1, -1, 401, - 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, - 422, -1, -1, 425, 426, -1, 428, -1, 430, 431, - 432, 433, 434, 435, -1, 437, 438, 439, -1, -1, - 442, 443, 444, 445, 446, -1, 448, 449, 450, 451, - 452, 453, 454, 455, -1, 457, 458, 459, 460, -1, - -1, 463, 464, 465, 466, -1, 468, 469, 470, 471, - 472, 473, 474, 475, -1, 477, -1, 479, 480, 481, - 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, + 28, 29, 30, -1, 32, 33, 34, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, + 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, + 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, + 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, + 78, 79, 80, -1, -1, -1, 84, 85, 86, 87, + 88, 89, -1, 91, 92, 93, -1, 95, 96, 97, + 98, 99, 100, -1, -1, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, + -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, + 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, + 148, -1, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, -1, 163, -1, 165, 166, 167, + 168, -1, 170, -1, 172, -1, -1, -1, 176, 177, + 178, -1, 180, 181, 182, -1, 184, 185, 186, 187, + -1, 189, 190, 191, 192, 193, 194, 195, -1, 197, + 198, 199, 200, -1, 202, 203, 204, 205, 206, 207, + 208, -1, 210, -1, 212, 213, 214, 215, 216, 217, + 218, 219, -1, 221, -1, 223, -1, -1, 226, -1, + 228, 229, 230, -1, 232, 233, 234, -1, -1, 237, + -1, 239, -1, -1, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, -1, 275, 276, 277, + 278, 279, -1, 281, 282, -1, 284, -1, 286, 287, + 288, 289, 290, 291, -1, 293, 294, -1, 296, 297, + 298, 299, -1, -1, 302, 303, 304, -1, 306, -1, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, -1, -1, -1, -1, 325, 326, 327, + -1, 329, 330, 331, 332, 333, 334, -1, 336, 337, + 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, + 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, + 358, 359, 360, 361, 362, 363, 364, 365, 366, -1, + 368, 369, -1, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, + -1, -1, 390, 391, 392, 393, 394, 395, 396, 397, + 398, -1, -1, 401, 402, 403, 404, -1, 406, 407, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 421, 422, -1, -1, 425, 426, -1, + 428, -1, 430, 431, 432, 433, 434, 435, -1, 437, + 438, 439, -1, -1, 442, 443, 444, 445, 446, -1, + 448, 449, 450, 451, 452, 453, 454, 455, -1, -1, + 458, 459, 460, -1, -1, 463, 464, 465, 466, -1, + 468, 469, 470, 471, 472, 473, 474, 475, -1, 477, + -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, + 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, - 33, 34, -1, -1, -1, 38, -1, -1, 41, -1, - 43, 44, 45, -1, 47, 48, 49, 50, 51, 52, - 53, -1, 55, 56, 57, 58, -1, 60, 61, 62, - 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, - 73, 74, -1, 76, 77, 78, 79, -1, -1, 82, - -1, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, -1, 95, 96, 97, 98, 99, 100, -1, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, - 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, - -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, - 143, -1, 145, 146, 147, 148, -1, 150, 151, 152, - 153, -1, 155, 156, 157, 158, 159, 160, -1, -1, - 163, -1, 165, 166, 167, 168, -1, 170, -1, 172, - 173, -1, 175, 176, 177, 178, 179, 180, 181, 182, - -1, -1, -1, 186, 187, -1, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 199, 200, -1, 202, - 203, 204, 205, 206, 207, 208, -1, 210, 211, -1, - 213, 214, 215, 216, 217, 218, 219, -1, 221, -1, - 223, 224, 225, 226, 227, 228, 229, 230, -1, 232, - 233, 234, -1, -1, 237, 238, 239, 240, -1, 242, - 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, - 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, - 273, 274, 275, 276, 277, 278, -1, -1, 281, 282, - 283, 284, -1, -1, 287, 288, 289, 290, 291, -1, - 293, 294, -1, -1, 297, 298, 299, -1, -1, 302, - 303, -1, 305, 306, 307, -1, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, -1, -1, - -1, -1, 325, 326, -1, 328, 329, 330, -1, 332, - 333, 334, -1, 336, 337, 338, 339, 340, 341, -1, - 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, - -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, - 363, 364, 365, 366, -1, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, - 383, 384, 385, 386, 387, -1, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, -1, 400, 401, 402, - 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 421, -1, - -1, -1, 425, 426, -1, 428, 429, 430, 431, 432, - 433, 434, 435, -1, 437, 438, 439, -1, -1, 442, - 443, -1, 445, -1, -1, 448, 449, 450, 451, 452, - 453, 454, 455, 456, -1, 458, 459, 460, 461, -1, - 463, 464, 465, 466, -1, 468, 469, 470, 471, 472, - -1, 474, 475, -1, 477, 478, 479, 480, 481, 482, - 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, - 493, 494, 495, 496, 3, -1, 5, -1, -1, -1, - -1, -1, -1, -1, -1, 508, 509, 510, 511, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, - 29, 30, -1, 32, 33, 34, 35, 36, -1, -1, + 29, 30, -1, 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, @@ -17834,7 +18094,7 @@ static const yytype_int16 yycheck[] = 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, -1, 275, 276, 277, 278, 279, -1, 281, 282, -1, 284, -1, 286, 287, 288, - 289, 290, 291, -1, 293, 294, -1, -1, 297, 298, + 289, 290, 291, -1, 293, 294, -1, 296, 297, 298, 299, -1, -1, 302, 303, 304, -1, 306, -1, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, -1, -1, -1, -1, 325, 326, 327, -1, @@ -17958,307 +18218,54 @@ static const yytype_int16 yycheck[] = 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 3, -1, 5, -1, -1, -1, -1, -1, -1, + 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, - 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, - 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, + 32, 33, 34, -1, -1, -1, 38, -1, -1, -1, + -1, 43, 44, 45, -1, 47, 48, 49, 50, 51, + 52, 53, -1, 55, 56, 57, 58, -1, 60, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, - 72, 73, 74, -1, 76, 77, 78, 79, 80, -1, - -1, -1, 84, 85, 86, 87, 88, 89, -1, 91, + 72, 73, 74, -1, 76, 77, 78, 79, -1, -1, + 82, -1, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, -1, 95, 96, 97, 98, 99, 100, -1, - -1, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, 148, -1, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 152, 153, -1, 155, 156, 157, 158, 159, 160, -1, -1, 163, -1, 165, 166, 167, 168, -1, 170, -1, - 172, -1, -1, -1, 176, 177, 178, -1, 180, 181, - 182, -1, 184, 185, 186, 187, -1, 189, 190, 191, - 192, 193, 194, 195, -1, 197, 198, 199, 200, -1, - 202, 203, 204, 205, 206, 207, 208, -1, 210, -1, - 212, 213, 214, 215, 216, 217, 218, 219, -1, 221, - -1, 223, -1, -1, 226, -1, 228, 229, 230, -1, - 232, 233, 234, -1, -1, 237, -1, 239, -1, -1, + 172, 173, -1, 175, 176, 177, -1, 179, 180, 181, + 182, -1, -1, -1, 186, 187, -1, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, -1, + 202, 203, 204, 205, 206, 207, 208, -1, 210, 211, + -1, 213, 214, 215, 216, 217, 218, 219, -1, 221, + -1, 223, 224, 225, 226, 227, 228, 229, 230, -1, + 232, 233, 234, -1, -1, 237, 238, 239, 240, -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, -1, 275, 276, 277, 278, 279, -1, 281, - 282, -1, 284, -1, 286, 287, 288, 289, 290, 291, - -1, 293, 294, -1, 296, 297, 298, 299, -1, -1, - 302, 303, 304, -1, 306, -1, 308, 309, 310, 311, + 272, 273, 274, 275, 276, 277, 278, -1, -1, 281, + 282, 283, 284, -1, -1, 287, 288, 289, 290, 291, + -1, 293, 294, -1, -1, 297, 298, 299, -1, -1, + 302, 303, -1, 305, 306, 307, -1, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, -1, - -1, -1, -1, 325, 326, 327, -1, 329, 330, 331, + -1, -1, -1, 325, 326, -1, 328, 329, 330, -1, 332, 333, 334, -1, 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, - 362, 363, 364, 365, 366, -1, 368, 369, -1, 371, + 362, 363, 364, 365, 366, -1, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, -1, -1, 390, 391, - 392, 393, 394, 395, 396, 397, 398, -1, -1, 401, + 382, 383, 384, 385, 386, 387, -1, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, - 422, -1, -1, 425, 426, -1, 428, -1, 430, 431, + -1, -1, -1, 425, 426, -1, 428, 429, 430, 431, 432, 433, 434, 435, -1, 437, 438, 439, -1, -1, - 442, 443, 444, 445, 446, -1, 448, 449, 450, 451, - 452, 453, 454, 455, -1, -1, 458, 459, 460, -1, + 442, 443, -1, 445, -1, -1, 448, 449, 450, 451, + 452, 453, 454, 455, 456, -1, 458, 459, 460, 461, -1, 463, 464, 465, 466, -1, 468, 469, 470, 471, - 472, 473, 474, 475, -1, 477, -1, 479, 480, 481, - 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, - 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, - 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, - 73, 74, -1, 76, 77, 78, 79, 80, -1, -1, - -1, 84, 85, 86, 87, 88, 89, -1, 91, 92, - 93, -1, 95, 96, 97, 98, 99, 100, -1, -1, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, - 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, - -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, - 143, -1, 145, 146, 147, 148, -1, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, - 163, -1, 165, 166, 167, 168, -1, 170, -1, 172, - -1, -1, -1, 176, 177, 178, -1, 180, 181, 182, - -1, 184, 185, 186, 187, -1, 189, 190, 191, 192, - 193, 194, 195, -1, 197, 198, 199, 200, -1, 202, - 203, 204, 205, 206, 207, 208, -1, 210, -1, 212, - 213, 214, 215, 216, 217, 218, 219, -1, 221, -1, - 223, -1, -1, 226, -1, 228, 229, 230, -1, 232, - 233, 234, -1, -1, 237, -1, 239, -1, -1, 242, - 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, - 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, - 273, -1, 275, 276, 277, 278, 279, -1, 281, 282, - -1, 284, -1, 286, 287, 288, 289, 290, 291, -1, - 293, 294, -1, -1, 297, 298, 299, -1, -1, 302, - 303, 304, -1, 306, -1, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, -1, -1, - -1, -1, 325, 326, 327, -1, 329, 330, 331, 332, - 333, 334, -1, 336, 337, 338, 339, 340, 341, -1, - 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, - -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, - 363, 364, 365, 366, -1, 368, 369, -1, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, - 383, 384, 385, 386, 387, -1, -1, 390, 391, 392, - 393, 394, 395, 396, 397, 398, -1, -1, 401, 402, - 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, - -1, -1, 425, 426, -1, 428, -1, 430, 431, 432, - 433, 434, 435, -1, 437, 438, 439, -1, -1, 442, - 443, 444, 445, 446, -1, 448, 449, 450, 451, 452, - 453, 454, 455, -1, -1, 458, 459, 460, -1, -1, - 463, 464, 465, 466, -1, 468, 469, 470, 471, 472, - 473, 474, 475, -1, 477, -1, 479, 480, 481, 482, - 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 3, - -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, - 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, - 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, - 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, - 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, - 74, -1, 76, 77, 78, 79, 80, -1, -1, -1, - 84, 85, 86, 87, 88, 89, -1, 91, 92, 93, - -1, 95, 96, 97, 98, 99, 100, -1, -1, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, - 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, - -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, - -1, 145, 146, 147, 148, -1, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, - -1, 165, 166, 167, 168, -1, 170, -1, 172, -1, - -1, -1, 176, 177, 178, -1, 180, 181, 182, -1, - 184, 185, 186, 187, -1, 189, 190, 191, 192, 193, - 194, 195, -1, 197, 198, 199, 200, -1, 202, 203, - 204, 205, 206, 207, 208, -1, 210, -1, 212, 213, - 214, 215, 216, 217, 218, 219, -1, 221, -1, 223, - -1, -1, 226, -1, 228, 229, 230, -1, 232, 233, - 234, -1, -1, 237, -1, 239, -1, -1, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, - -1, 275, 276, 277, 278, 279, -1, 281, 282, -1, - 284, -1, 286, 287, 288, 289, 290, 291, -1, 293, - 294, -1, 296, 297, 298, 299, -1, -1, 302, 303, - 304, -1, 306, -1, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, -1, -1, -1, - -1, 325, 326, 327, -1, 329, 330, 331, 332, 333, - 334, -1, 336, 337, 338, 339, 340, 341, -1, 343, - 344, 345, 346, 347, 348, 349, 350, 351, 352, -1, - 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, - 364, 365, 366, -1, 368, 369, -1, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, - 384, 385, 386, 387, -1, -1, 390, 391, 392, 393, - 394, 395, 396, 397, 398, -1, -1, 401, 402, 403, - 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 421, 422, -1, - -1, 425, 426, -1, 428, -1, 430, 431, 432, 433, - 434, 435, -1, 437, 438, 439, -1, -1, 442, 443, - 444, 445, 446, -1, 448, 449, 450, 451, 452, 453, - 454, 455, -1, -1, 458, 459, 460, -1, -1, 463, - 464, 465, 466, -1, 468, 469, 470, 471, 472, 473, - 474, 475, -1, 477, -1, 479, 480, 481, 482, 483, - 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, - 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, - 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, - -1, -1, -1, 38, -1, -1, -1, -1, 43, 44, - 45, -1, 47, 48, 49, 50, 51, 52, 53, -1, - 55, 56, 57, 58, -1, 60, 61, 62, 63, 64, - 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, - -1, 76, 77, 78, 79, -1, -1, 82, -1, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, -1, - 95, 96, 97, 98, 99, 100, -1, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, - 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, - 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, - 145, 146, 147, 148, -1, 150, 151, 152, 153, -1, - 155, 156, 157, 158, 159, 160, -1, -1, 163, -1, - 165, 166, 167, 168, -1, 170, -1, 172, 173, -1, - 175, 176, 177, -1, 179, 180, 181, 182, -1, -1, - -1, 186, 187, -1, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 200, -1, 202, 203, 204, - 205, 206, 207, 208, -1, 210, 211, -1, 213, 214, - 215, 216, 217, 218, 219, -1, 221, -1, 223, 224, - 225, 226, 227, 228, 229, 230, -1, 232, 233, 234, - -1, -1, 237, 238, 239, 240, -1, 242, 243, 244, - 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, - 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, -1, -1, 281, 282, 283, 284, - -1, -1, 287, 288, 289, 290, 291, -1, 293, 294, - -1, -1, 297, 298, 299, -1, -1, 302, 303, -1, - 305, 306, 307, -1, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, -1, -1, -1, -1, - 325, 326, -1, 328, 329, 330, -1, 332, 333, 334, - -1, 336, 337, 338, 339, 340, 341, -1, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, -1, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, -1, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, - -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 421, -1, -1, -1, - 425, 426, -1, 428, 429, 430, 431, 432, 433, 434, - 435, -1, 437, 438, 439, -1, -1, 442, 443, -1, - 445, -1, -1, 448, 449, 450, 451, 452, 453, 454, - 455, 456, -1, 458, 459, 460, 461, -1, 463, 464, - 465, 466, -1, 468, 469, 470, 471, 472, -1, 474, - 475, -1, 477, 478, 479, 480, 481, 482, 483, 484, - 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, - 495, 496, 3, -1, 5, -1, -1, -1, -1, -1, - -1, -1, -1, 508, 509, 510, 511, -1, -1, -1, - -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, - -1, 32, 33, 34, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, - 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, - 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, - 71, 72, 73, 74, -1, 76, 77, 78, 79, 80, - -1, -1, -1, 84, 85, 86, 87, 88, 89, -1, - 91, 92, 93, -1, 95, 96, 97, 98, 99, 100, - -1, -1, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, - 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, - 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, - 141, 142, 143, -1, 145, 146, 147, 148, -1, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, -1, 165, 166, 167, 168, -1, 170, - -1, 172, -1, -1, -1, 176, 177, 178, -1, 180, - 181, 182, -1, 184, 185, 186, 187, -1, 189, 190, - 191, 192, 193, 194, 195, -1, 197, 198, 199, 200, - -1, 202, 203, 204, 205, 206, 207, 208, -1, 210, - -1, 212, 213, 214, 215, 216, 217, 218, 219, -1, - 221, -1, 223, -1, -1, 226, -1, 228, 229, 230, - -1, 232, 233, 234, -1, -1, 237, -1, 239, -1, - -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, 273, -1, 275, 276, 277, 278, 279, -1, - 281, 282, -1, 284, -1, 286, 287, 288, 289, 290, - 291, -1, 293, 294, -1, -1, 297, 298, 299, -1, - -1, 302, 303, 304, -1, 306, -1, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - -1, -1, -1, -1, 325, 326, 327, -1, 329, 330, - 331, 332, 333, 334, -1, 336, 337, 338, 339, 340, - 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, - 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, 366, -1, 368, 369, -1, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385, 386, 387, -1, -1, 390, - 391, 392, 393, 394, 395, 396, 397, 398, -1, -1, - 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 421, 422, -1, -1, 425, 426, 427, 428, -1, 430, - 431, 432, 433, 434, 435, -1, 437, 438, 439, -1, - -1, 442, 443, 444, 445, 446, -1, 448, 449, 450, - 451, 452, 453, 454, 455, -1, -1, 458, 459, 460, - -1, -1, 463, 464, 465, 466, -1, 468, 469, 470, - 471, 472, 473, 474, 475, -1, 477, -1, 479, 480, - 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, - 32, 33, 34, -1, -1, -1, 38, -1, -1, -1, - -1, 43, 44, 45, -1, 47, 48, 49, 50, 51, - 52, 53, -1, 55, 56, 57, 58, -1, 60, 61, - 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, - 72, 73, 74, -1, 76, 77, 78, 79, -1, -1, - 82, -1, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, -1, 95, 96, 97, 98, 99, 100, -1, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, - 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, - 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, - 142, 143, -1, 145, 146, 147, 148, -1, 150, 151, - 152, 153, -1, 155, 156, 157, 158, 159, 160, -1, - -1, 163, -1, 165, 166, 167, 168, -1, 170, -1, - 172, 173, -1, 175, 176, 177, -1, 179, 180, 181, - 182, -1, -1, -1, 186, 187, -1, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, -1, - 202, 203, 204, 205, 206, 207, 208, -1, 210, 211, - -1, 213, 214, 215, 216, 217, 218, 219, -1, 221, - -1, 223, 224, 225, 226, 227, 228, 229, 230, -1, - 232, 233, 234, -1, -1, 237, 238, 239, 240, -1, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, -1, -1, 281, - 282, 283, 284, -1, -1, 287, 288, 289, 290, 291, - -1, 293, 294, -1, -1, 297, 298, 299, -1, -1, - 302, 303, -1, 305, 306, 307, -1, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, -1, - -1, -1, -1, 325, 326, -1, 328, 329, 330, -1, - 332, 333, 334, -1, 336, 337, 338, 339, 340, 341, - -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, - 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, - 362, 363, 364, 365, 366, -1, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, -1, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, - -1, -1, -1, 425, 426, -1, 428, 429, 430, 431, - 432, 433, 434, 435, -1, 437, 438, 439, -1, -1, - 442, 443, -1, 445, -1, -1, 448, 449, 450, 451, - 452, 453, 454, 455, 456, -1, 458, 459, 460, 461, - -1, 463, 464, 465, 466, -1, 468, 469, 470, 471, - 472, -1, 474, 475, -1, 477, 478, 479, 480, 481, + 472, -1, 474, 475, -1, 477, 478, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, 508, 509, 510, 511, @@ -18302,7 +18309,7 @@ static const yytype_int16 yycheck[] = -1, -1, 390, 391, 392, 393, 394, 395, 396, 397, 398, -1, -1, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 421, 422, -1, -1, 425, 426, -1, + 418, 419, 420, 421, 422, -1, -1, 425, 426, 427, 428, -1, 430, 431, 432, 433, 434, 435, -1, 437, 438, 439, -1, -1, 442, 443, 444, 445, 446, -1, 448, 449, 450, 451, 452, 453, 454, 455, -1, -1, @@ -18311,22 +18318,275 @@ static const yytype_int16 yycheck[] = -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, - 508, 509, 510, 511, 3, -1, 5, -1, -1, -1, + 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, - 29, 30, -1, 32, 33, 34, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, - 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, - -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, + 29, 30, -1, 32, 33, 34, -1, -1, -1, 38, + -1, -1, -1, -1, 43, 44, 45, -1, 47, 48, + 49, 50, 51, 52, 53, -1, 55, 56, 57, 58, + -1, 60, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, 78, - 79, 80, -1, -1, -1, 84, 85, 86, 87, 88, - 89, -1, 91, 92, 93, -1, 95, 96, 97, 98, - 99, 100, -1, -1, 103, 104, 105, 106, 107, 108, + 79, -1, -1, 82, -1, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, -1, 95, 96, 97, 98, + 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, 148, - -1, 150, 151, 152, 153, 154, 155, 156, 157, 158, + -1, 150, 151, 152, 153, -1, 155, 156, 157, 158, + 159, 160, -1, -1, 163, -1, 165, 166, 167, 168, + -1, 170, -1, 172, 173, -1, 175, 176, 177, -1, + 179, 180, 181, 182, -1, -1, -1, 186, 187, -1, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, -1, 202, 203, 204, 205, 206, 207, 208, + -1, 210, 211, -1, 213, 214, 215, 216, 217, 218, + 219, -1, 221, -1, 223, 224, 225, 226, 227, 228, + 229, 230, -1, 232, 233, 234, -1, -1, 237, 238, + 239, 240, -1, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, + -1, -1, 281, 282, 283, 284, -1, -1, 287, 288, + 289, 290, 291, -1, 293, 294, -1, -1, 297, 298, + 299, -1, -1, 302, 303, -1, 305, 306, 307, -1, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, -1, -1, -1, -1, 325, 326, -1, 328, + 329, 330, -1, 332, 333, 334, -1, 336, 337, 338, + 339, 340, 341, -1, 343, 344, 345, 346, 347, 348, + 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, + 359, 360, 361, 362, 363, 364, 365, 366, -1, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, 382, 383, 384, 385, 386, 387, -1, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, -1, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 421, -1, -1, -1, 425, 426, -1, 428, + 429, 430, 431, 432, 433, 434, 435, -1, 437, 438, + 439, -1, -1, 442, 443, -1, 445, -1, -1, 448, + 449, 450, 451, 452, 453, 454, 455, 456, -1, 458, + 459, 460, 461, -1, 463, 464, 465, 466, -1, 468, + 469, 470, 471, 472, -1, 474, 475, -1, 477, 478, + 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, + -1, -1, 491, 492, 493, 494, 495, 496, 3, -1, + 5, -1, -1, -1, -1, -1, -1, -1, -1, 508, + 509, 510, 511, -1, -1, -1, -1, -1, 23, 24, + 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, + 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, + 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, + 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, + -1, 76, 77, 78, 79, 80, -1, -1, -1, 84, + 85, 86, 87, 88, 89, -1, 91, 92, 93, -1, + 95, 96, 97, 98, 99, 100, -1, -1, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, + 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, + 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, + 145, 146, 147, 148, -1, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, -1, 163, -1, + 165, 166, 167, 168, -1, 170, -1, 172, -1, -1, + -1, 176, 177, 178, -1, 180, 181, 182, -1, 184, + 185, 186, 187, -1, 189, 190, 191, 192, 193, 194, + 195, -1, 197, 198, 199, 200, -1, 202, 203, 204, + 205, 206, 207, 208, -1, 210, -1, 212, 213, 214, + 215, 216, 217, 218, 219, -1, 221, -1, 223, -1, + -1, 226, -1, 228, 229, 230, -1, 232, 233, 234, + -1, -1, 237, -1, 239, -1, -1, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, -1, + 275, 276, 277, 278, 279, -1, 281, 282, -1, 284, + -1, 286, 287, 288, 289, 290, 291, -1, 293, 294, + -1, -1, 297, 298, 299, -1, -1, 302, 303, 304, + -1, 306, -1, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, -1, -1, -1, -1, + 325, 326, 327, -1, 329, 330, 331, 332, 333, 334, + -1, 336, 337, 338, 339, 340, 341, -1, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, -1, 368, 369, -1, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, -1, -1, 390, 391, 392, 393, 394, + 395, 396, 397, 398, -1, -1, 401, 402, 403, 404, + -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 421, 422, -1, -1, + 425, 426, -1, 428, -1, 430, 431, 432, 433, 434, + 435, -1, 437, 438, 439, -1, -1, 442, 443, 444, + 445, 446, -1, 448, 449, 450, 451, 452, 453, 454, + 455, -1, -1, 458, 459, 460, -1, -1, 463, 464, + 465, 466, -1, 468, 469, 470, 471, 472, 473, 474, + 475, -1, 477, -1, 479, 480, 481, 482, 483, 484, + 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, + 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 510, 511, 3, -1, 5, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, + 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 44, 45, + -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, + -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, + -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, + 76, 77, 78, 79, 80, -1, -1, -1, 84, 85, + 86, 87, 88, 89, -1, 91, 92, 93, -1, 95, + 96, 97, 98, 99, 100, -1, -1, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, + 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, + 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, + 146, 147, 148, -1, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, -1, 163, -1, 165, + 166, 167, 168, -1, 170, -1, 172, -1, -1, -1, + 176, 177, 178, -1, 180, 181, 182, -1, 184, 185, + 186, 187, -1, 189, 190, 191, 192, 193, 194, 195, + -1, 197, 198, 199, 200, -1, 202, 203, 204, 205, + 206, 207, 208, -1, 210, -1, 212, 213, 214, 215, + 216, 217, 218, 219, -1, 221, -1, 223, -1, -1, + 226, -1, 228, 229, 230, -1, 232, 233, 234, -1, + -1, 237, -1, 239, -1, -1, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, -1, 275, + 276, 277, 278, 279, -1, 281, 282, -1, 284, -1, + 286, 287, 288, 289, 290, 291, -1, 293, 294, -1, + -1, 297, 298, 299, -1, -1, 302, 303, 304, -1, + 306, -1, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, -1, -1, -1, -1, 325, + 326, 327, -1, 329, 330, 331, 332, 333, 334, -1, + 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, + 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, + 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, + 366, -1, 368, 369, -1, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, -1, -1, 390, 391, 392, 393, 394, 395, + 396, 397, 398, -1, -1, 401, 402, 403, 404, -1, + 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 421, 422, -1, -1, 425, + 426, -1, 428, -1, 430, 431, 432, 433, 434, 435, + -1, 437, 438, 439, -1, -1, 442, 443, 444, 445, + 446, -1, 448, 449, 450, 451, 452, 453, 454, 455, + -1, -1, 458, 459, 460, -1, -1, 463, 464, 465, + 466, -1, 468, 469, 470, 471, 472, 473, 474, 475, + -1, 477, -1, 479, 480, 481, 482, 483, 484, 485, + -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 44, 45, -1, + -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, + 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, + -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, + 77, 78, 79, 80, -1, -1, -1, 84, 85, 86, + 87, 88, 89, -1, 91, 92, 93, -1, 95, 96, + 97, 98, 99, 100, -1, -1, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, + -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, + 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, + 147, 148, -1, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, -1, 163, -1, 165, 166, + 167, 168, -1, 170, -1, 172, -1, -1, -1, 176, + 177, 178, -1, 180, 181, 182, -1, 184, 185, 186, + 187, -1, 189, 190, 191, 192, 193, 194, 195, -1, + 197, 198, 199, 200, -1, 202, 203, 204, 205, 206, + 207, 208, -1, 210, -1, 212, 213, 214, 215, 216, + 217, 218, 219, -1, 221, -1, 223, -1, -1, 226, + -1, 228, 229, 230, -1, 232, 233, 234, -1, -1, + 237, -1, 239, -1, -1, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, -1, 275, 276, + 277, 278, 279, -1, 281, 282, -1, 284, -1, 286, + 287, 288, 289, 290, 291, -1, 293, 294, -1, -1, + 297, 298, 299, -1, -1, 302, 303, 304, -1, 306, + -1, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, -1, -1, -1, -1, 325, 326, + 327, -1, 329, 330, 331, 332, 333, 334, -1, 336, + 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, + 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, + -1, 368, 369, -1, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, + 387, -1, -1, 390, 391, 392, 393, 394, 395, 396, + 397, 398, -1, -1, 401, 402, 403, 404, -1, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, -1, -1, 425, 426, + -1, 428, -1, 430, 431, 432, 433, 434, 435, -1, + 437, 438, 439, -1, -1, 442, 443, 444, 445, 446, + -1, 448, 449, 450, 451, 452, 453, 454, 455, -1, + -1, 458, 459, 460, -1, -1, 463, 464, 465, 466, + -1, 468, 469, 470, 471, 472, 473, 474, 475, -1, + 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, + -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 3, -1, 5, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, + 28, 29, 30, -1, 32, 33, 34, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, + 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, + 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, + 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, + 78, 79, 80, -1, -1, -1, 84, 85, 86, 87, + 88, 89, -1, 91, 92, 93, -1, 95, 96, 97, + 98, 99, 100, -1, -1, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, + -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, + 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, + 148, -1, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, -1, 163, -1, 165, 166, 167, + 168, -1, 170, -1, 172, -1, -1, -1, 176, 177, + 178, -1, 180, 181, 182, -1, 184, 185, 186, 187, + -1, 189, 190, 191, 192, 193, 194, 195, -1, 197, + 198, 199, 200, -1, 202, 203, 204, 205, 206, 207, + 208, -1, 210, -1, 212, 213, 214, 215, 216, 217, + 218, 219, -1, 221, -1, 223, -1, -1, 226, -1, + 228, 229, 230, -1, 232, 233, 234, -1, -1, 237, + -1, 239, -1, -1, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, -1, 275, 276, 277, + 278, 279, -1, 281, 282, -1, 284, -1, 286, 287, + 288, 289, 290, 291, -1, 293, 294, -1, -1, 297, + 298, 299, -1, -1, 302, 303, 304, -1, 306, -1, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, -1, -1, -1, -1, 325, 326, 327, + -1, 329, 330, 331, 332, 333, 334, -1, 336, 337, + 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, + 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, + 358, 359, 360, 361, 362, 363, 364, 365, 366, -1, + 368, 369, -1, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, + -1, -1, 390, 391, 392, 393, 394, 395, 396, 397, + 398, -1, -1, 401, 402, 403, 404, -1, 406, 407, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 421, 422, -1, -1, 425, 426, -1, + 428, -1, 430, 431, 432, 433, 434, 435, -1, 437, + 438, 439, -1, -1, 442, 443, 444, 445, 446, -1, + 448, 449, 450, 451, 452, 453, 454, 455, -1, -1, + 458, 459, 460, -1, -1, 463, 464, 465, 466, -1, + 468, 469, 470, 471, 472, 473, 474, 475, -1, 477, + -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, + 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 3, -1, 5, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, + 29, 30, -1, 32, 33, 34, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, + 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, + -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, + 69, 70, 71, 72, 73, 74, -1, 76, 77, 78, + 79, 80, -1, -1, -1, 84, 85, 86, 87, 88, + 89, -1, 91, 92, 93, -1, 95, 96, 97, 98, + 99, 100, -1, -1, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, + 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, + 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, + 139, -1, 141, 142, 143, -1, 145, 146, 147, 148, + -1, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, -1, 165, 166, 167, 168, -1, 170, -1, 172, -1, -1, -1, 176, 177, 178, -1, 180, 181, 182, -1, 184, 185, 186, 187, -1, @@ -18362,10 +18622,10 @@ static const yytype_int16 yycheck[] = 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, + 509, 510, 511, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, -1, -1, -1, -1, -1, + 30, -1, 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, @@ -18617,10 +18877,10 @@ static const yytype_int16 yycheck[] = 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, - 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, + -1, -1, -1, -1, -1, -1, 41, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, @@ -18667,11 +18927,11 @@ static const yytype_int16 yycheck[] = 475, -1, 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 3, -1, 5, + 505, 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 44, 45, + -1, -1, -1, -1, -1, 41, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, @@ -18718,10 +18978,10 @@ static const yytype_int16 yycheck[] = -1, 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 3, -1, 5, -1, + 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, - 27, 28, 29, 30, -1, 32, 33, 34, -1, -1, + 27, 28, 29, 30, 31, 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, @@ -18769,11 +19029,11 @@ static const yytype_int16 yycheck[] = 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, + 507, 508, 509, 510, 511, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, -1, -1, - -1, -1, -1, 41, -1, -1, 44, 45, -1, -1, + -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, @@ -18820,11 +19080,11 @@ static const yytype_int16 yycheck[] = -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, - 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, + 508, 509, 510, 511, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, -1, -1, -1, - -1, -1, 41, -1, -1, 44, 45, -1, -1, 48, + -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, 78, @@ -18871,10 +19131,10 @@ static const yytype_int16 yycheck[] = 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, + 509, 510, 511, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, -1, -1, -1, -1, -1, + 30, -1, 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, @@ -19126,7 +19386,7 @@ static const yytype_int16 yycheck[] = 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 3, -1, - 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, @@ -19176,7 +19436,7 @@ static const yytype_int16 yycheck[] = 475, -1, 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 3, -1, 5, + 505, 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, @@ -19227,7 +19487,7 @@ static const yytype_int16 yycheck[] = -1, 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 3, -1, 5, -1, + 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, -1, @@ -19485,7 +19745,7 @@ static const yytype_int16 yycheck[] = 511, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, - 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, + 32, 33, 34, -1, -1, -1, -1, -1, -1, 41, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, @@ -19521,7 +19781,7 @@ static const yytype_int16 yycheck[] = 362, 363, 364, 365, 366, -1, 368, 369, -1, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, -1, -1, 390, 391, - 392, 393, 394, 395, 396, 397, 398, -1, -1, 401, + 392, 393, 394, -1, 396, 397, 398, -1, -1, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, -1, -1, 425, 426, -1, 428, -1, 430, 431, @@ -19638,7 +19898,7 @@ static const yytype_int16 yycheck[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, - -1, -1, -1, -1, -1, -1, 41, -1, -1, 44, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, @@ -19674,7 +19934,7 @@ static const yytype_int16 yycheck[] = 365, 366, -1, 368, 369, -1, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, -1, -1, 390, 391, 392, 393, 394, - -1, 396, 397, 398, -1, -1, 401, 402, 403, 404, + 395, 396, 397, 398, -1, -1, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, -1, -1, 425, 426, -1, 428, -1, 430, 431, 432, 433, 434, @@ -19689,358 +19949,255 @@ static const yytype_int16 yycheck[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 44, 45, - -1, -1, 48, 49, -1, 51, 52, 53, 54, 55, - -1, 57, 58, -1, -1, 61, 62, 63, 64, 65, + -1, -1, 38, -1, -1, -1, -1, 43, 44, 45, + -1, 47, 48, 49, 50, 51, 52, 53, -1, 55, + 56, 57, 58, -1, 60, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, - 76, 77, 78, 79, 80, -1, -1, -1, 84, 85, - 86, 87, 88, 89, -1, 91, 92, 93, -1, 95, - 96, 97, 98, 99, 100, -1, -1, 103, 104, 105, + 76, 77, 78, 79, -1, -1, 82, -1, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, -1, 95, + 96, 97, 98, 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, - 146, 147, 148, -1, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, -1, 165, - 166, 167, 168, -1, 170, -1, 172, -1, -1, -1, - 176, 177, 178, -1, 180, 181, 182, -1, 184, 185, + 146, 147, 148, -1, 150, 151, 152, 153, -1, 155, + 156, 157, 158, 159, 160, -1, -1, 163, -1, 165, + 166, 167, 168, -1, 170, -1, 172, 173, -1, 175, + 176, 177, 178, 179, 180, 181, 182, -1, -1, -1, 186, 187, -1, 189, 190, 191, 192, 193, 194, 195, - -1, 197, 198, 199, 200, -1, 202, 203, 204, 205, - 206, 207, 208, -1, 210, -1, 212, 213, 214, 215, - 216, 217, 218, 219, -1, 221, -1, 223, -1, -1, - 226, -1, 228, 229, 230, -1, 232, 233, 234, -1, - -1, 237, -1, 239, -1, -1, 242, 243, 244, 245, + 196, 197, 198, 199, 200, -1, 202, 203, 204, 205, + 206, 207, 208, -1, 210, 211, -1, 213, 214, 215, + 216, 217, 218, 219, -1, 221, -1, 223, 224, 225, + 226, 227, 228, 229, 230, -1, 232, 233, 234, -1, + -1, 237, 238, 239, 240, -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, -1, 275, - 276, 277, 278, 279, -1, 281, 282, -1, 284, -1, - 286, 287, 288, 289, 290, 291, -1, 293, 294, -1, - -1, 297, 298, 299, -1, -1, 302, 303, 304, -1, - 306, -1, 308, 309, 310, 311, 312, 313, 314, 315, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, -1, -1, 281, 282, 283, 284, -1, + -1, 287, 288, 289, 290, 291, -1, 293, 294, -1, + -1, 297, 298, 299, -1, -1, 302, 303, -1, 305, + 306, 307, -1, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, -1, -1, -1, -1, 325, - 326, 327, -1, 329, 330, 331, 332, 333, 334, -1, + 326, -1, 328, 329, 330, -1, 332, 333, 334, -1, 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, - 366, -1, 368, 369, -1, 371, 372, 373, 374, 375, + 366, -1, 368, 369, 370, 371, 372, 373, -1, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, - 386, 387, -1, -1, 390, 391, 392, 393, 394, 395, - 396, 397, 398, -1, -1, 401, 402, 403, 404, -1, + 386, 387, -1, 389, 390, 391, 392, 393, 394, 395, + -1, 397, 398, -1, 400, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 421, 422, -1, -1, 425, - 426, -1, 428, -1, 430, 431, 432, 433, 434, 435, - -1, 437, 438, 439, -1, -1, 442, 443, 444, 445, - 446, -1, 448, 449, 450, 451, 452, 453, 454, 455, - -1, -1, 458, 459, 460, -1, -1, 463, 464, 465, - 466, -1, 468, 469, 470, 471, 472, 473, 474, 475, - -1, 477, -1, 479, 480, 481, 482, 483, 484, 485, + 416, 417, 418, 419, 420, 421, -1, -1, -1, 425, + 426, -1, 428, 429, 430, 431, 432, 433, 434, 435, + -1, 437, 438, 439, -1, -1, 442, 443, -1, 445, + -1, -1, 448, 449, 450, 451, 452, 453, 454, 455, + -1, -1, 458, 459, 460, 461, -1, 463, 464, 465, + 466, -1, 468, 469, 470, 471, 472, -1, 474, 475, + -1, 477, 478, 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 3, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, - 27, 28, 29, 30, -1, 32, 33, 34, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 44, 45, -1, - -1, 48, 49, -1, 51, 52, 53, 54, 55, -1, - 57, 58, -1, -1, 61, 62, 63, 64, 65, -1, - -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, - 77, 78, 79, 80, -1, -1, -1, 84, 85, 86, - 87, 88, 89, -1, 91, 92, 93, -1, 95, 96, - 97, 98, 99, 100, -1, -1, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, - -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, - 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, - 147, 148, -1, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, -1, 163, -1, 165, 166, - 167, 168, -1, 170, -1, 172, -1, -1, -1, 176, - 177, 178, -1, 180, 181, 182, -1, 184, 185, 186, - 187, -1, 189, 190, 191, 192, 193, 194, 195, -1, - 197, 198, 199, 200, -1, 202, 203, 204, 205, 206, - 207, 208, -1, 210, -1, 212, 213, 214, 215, 216, - 217, 218, 219, -1, 221, -1, 223, -1, -1, 226, - -1, 228, 229, 230, -1, 232, 233, 234, -1, -1, - 237, -1, 239, -1, -1, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, -1, 275, 276, - 277, 278, 279, -1, 281, 282, -1, 284, -1, 286, - 287, 288, 289, 290, 291, -1, 293, 294, -1, -1, - 297, 298, 299, -1, -1, 302, 303, 304, -1, 306, - -1, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, -1, -1, -1, -1, 325, 326, - 327, -1, 329, 330, 331, 332, 333, 334, -1, 336, - 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, - 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, - 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, - -1, 368, 369, -1, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, - 387, -1, -1, 390, 391, 392, 393, 394, 395, 396, - 397, 398, -1, -1, 401, 402, 403, 404, -1, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 421, 422, -1, -1, 425, 426, - -1, 428, -1, 430, 431, 432, 433, 434, 435, -1, - 437, 438, 439, -1, -1, 442, 443, 444, 445, 446, - -1, 448, 449, 450, 451, 452, 453, 454, 455, -1, - -1, 458, 459, 460, -1, -1, 463, 464, 465, 466, - -1, 468, 469, 470, 471, 472, 473, 474, 475, -1, - 477, -1, 479, 480, 481, 482, 483, 484, 485, -1, - -1, 488, -1, -1, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 3, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 496, 3, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 508, 509, 510, 511, -1, -1, -1, -1, + -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, + 32, 33, 34, -1, -1, -1, 38, -1, -1, -1, + -1, 43, 44, 45, -1, 47, 48, 49, 50, 51, + 52, 53, -1, 55, 56, 57, 58, -1, 60, 61, + 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, + 72, 73, 74, -1, 76, 77, 78, 79, -1, -1, + 82, -1, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, -1, 95, 96, 97, 98, 99, 100, -1, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, + 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, + 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, + 142, 143, -1, 145, 146, 147, 148, -1, 150, 151, + 152, 153, -1, 155, 156, 157, 158, 159, 160, -1, + -1, 163, -1, 165, 166, 167, 168, -1, 170, -1, + 172, 173, -1, 175, 176, 177, -1, 179, 180, 181, + 182, -1, -1, -1, 186, 187, -1, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, -1, + 202, 203, 204, 205, 206, 207, 208, -1, 210, 211, + -1, 213, 214, 215, 216, 217, 218, 219, -1, 221, + -1, 223, 224, 225, 226, 227, 228, 229, 230, -1, + 232, 233, 234, -1, -1, 237, 238, 239, 240, -1, + 242, 243, 244, 245, 246, 247, 248, 249, -1, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, -1, -1, 281, + 282, 283, 284, -1, -1, 287, 288, 289, 290, 291, + -1, 293, 294, -1, -1, 297, 298, 299, -1, -1, + 302, 303, -1, 305, 306, 307, -1, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, -1, + -1, -1, -1, 325, 326, -1, 328, 329, 330, -1, + 332, 333, 334, -1, 336, 337, 338, 339, 340, 341, + -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, + 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, -1, 368, 369, 370, 371, + 372, 373, -1, 375, 376, 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, 387, -1, 389, 390, 391, + 392, 393, 394, 395, -1, 397, 398, -1, 400, 401, + 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, -1, 421, + -1, -1, -1, 425, 426, -1, 428, 429, 430, 431, + 432, 433, 434, 435, -1, 437, 438, 439, -1, -1, + 442, 443, -1, 445, -1, -1, 448, 449, 450, 451, + 452, 453, 454, 455, -1, -1, 458, 459, 460, 461, + -1, 463, 464, 465, 466, -1, 468, 469, 470, 471, + 472, -1, 474, 475, -1, 477, 478, 479, 480, 481, + 482, 483, 484, 485, -1, -1, 488, -1, -1, 491, + 492, 493, 494, 495, 496, 3, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 508, 509, 510, 511, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 44, 45, -1, -1, - 48, 49, -1, 51, 52, 53, 54, 55, -1, 57, - 58, -1, -1, 61, 62, 63, 64, 65, -1, -1, + 38, -1, -1, -1, -1, 43, 44, 45, -1, 47, + 48, 49, 50, 51, 52, 53, -1, 55, 56, 57, + 58, -1, 60, 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, -1, 76, 77, - 78, 79, 80, -1, -1, -1, 84, 85, 86, 87, - 88, 89, -1, 91, 92, 93, -1, 95, 96, 97, - 98, 99, 100, -1, -1, 103, 104, 105, 106, 107, + 78, 79, -1, -1, 82, -1, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, -1, 95, 96, 97, + 98, 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, 145, 146, 147, - 148, -1, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, -1, 163, -1, 165, 166, 167, - 168, -1, 170, -1, 172, -1, -1, -1, 176, 177, - 178, -1, 180, 181, 182, -1, 184, 185, 186, 187, - -1, 189, 190, 191, 192, 193, 194, 195, -1, 197, + 148, -1, 150, 151, 152, 153, -1, 155, 156, 157, + 158, 159, 160, -1, -1, 163, -1, 165, 166, 167, + 168, -1, 170, -1, 172, 173, -1, 175, 176, 177, + -1, 179, 180, 181, 182, -1, -1, -1, 186, 187, + -1, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, -1, 202, 203, 204, 205, 206, 207, - 208, -1, 210, -1, 212, 213, 214, 215, 216, 217, - 218, 219, -1, 221, -1, 223, -1, -1, 226, -1, + 208, -1, 210, 211, -1, 213, 214, 215, 216, 217, + 218, 219, -1, 221, -1, 223, 224, 225, 226, 227, 228, 229, 230, -1, 232, 233, 234, -1, -1, 237, - -1, 239, -1, -1, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 238, 239, 240, -1, 242, 243, 244, 245, 246, 247, + 248, 249, -1, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, -1, 275, 276, 277, - 278, 279, -1, 281, 282, -1, 284, -1, 286, 287, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, -1, -1, 281, 282, 283, 284, -1, -1, 287, 288, 289, 290, 291, -1, 293, 294, -1, -1, 297, - 298, 299, -1, -1, 302, 303, 304, -1, 306, -1, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, -1, -1, -1, -1, 325, 326, 327, - -1, 329, 330, 331, 332, 333, 334, -1, 336, 337, + 298, 299, -1, -1, 302, 303, -1, 305, 306, 307, + -1, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, -1, -1, -1, -1, 325, 326, -1, + 328, 329, 330, -1, 332, 333, 334, -1, 336, 337, 338, 339, 340, 341, -1, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, -1, - 368, 369, -1, 371, 372, 373, 374, 375, 376, 377, + 368, 369, 370, 371, 372, 373, -1, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, - -1, -1, 390, 391, 392, 393, 394, 395, 396, 397, - 398, -1, -1, 401, 402, 403, 404, -1, 406, 407, + -1, 389, 390, 391, 392, 393, 394, 395, -1, 397, + 398, -1, 400, 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 421, 422, -1, -1, 425, 426, -1, - 428, -1, 430, 431, 432, 433, 434, 435, -1, 437, - 438, 439, -1, -1, 442, 443, 444, 445, 446, -1, - 448, 449, 450, 451, 452, 453, 454, 455, -1, -1, - 458, 459, 460, -1, -1, 463, 464, 465, 466, -1, - 468, 469, 470, 471, 472, 473, 474, 475, -1, 477, - -1, 479, 480, 481, 482, 483, 484, 485, -1, -1, - 488, -1, -1, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, - 508, 509, 510, 511, 3, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, - 29, 30, -1, 32, 33, 34, -1, -1, -1, 38, - -1, -1, -1, -1, 43, 44, 45, -1, 47, 48, - 49, 50, 51, 52, 53, -1, 55, 56, 57, 58, - -1, 60, 61, 62, 63, 64, 65, -1, -1, 68, - 69, 70, 71, 72, 73, 74, -1, 76, 77, 78, - 79, -1, -1, 82, -1, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, -1, 95, 96, 97, 98, - 99, 100, -1, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, -1, - 119, -1, 121, 122, 123, 124, 125, 126, -1, -1, - 129, 130, 131, 132, -1, -1, 135, 136, 137, 138, - 139, -1, 141, 142, 143, -1, 145, 146, 147, 148, - -1, 150, 151, 152, 153, -1, 155, 156, 157, 158, - 159, 160, -1, -1, 163, -1, 165, 166, 167, 168, - -1, 170, -1, 172, 173, -1, 175, 176, 177, 178, - 179, 180, 181, 182, -1, -1, -1, 186, 187, -1, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, -1, 202, 203, 204, 205, 206, 207, 208, - -1, 210, 211, -1, 213, 214, 215, 216, 217, 218, - 219, -1, 221, -1, 223, 224, 225, 226, 227, 228, - 229, 230, -1, 232, 233, 234, -1, -1, 237, 238, - 239, 240, -1, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - -1, -1, 281, 282, 283, 284, -1, -1, 287, 288, - 289, 290, 291, -1, 293, 294, -1, -1, 297, 298, - 299, -1, -1, 302, 303, -1, 305, 306, 307, -1, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, -1, -1, -1, -1, 325, 326, -1, 328, - 329, 330, -1, 332, 333, 334, -1, 336, 337, 338, - 339, 340, 341, -1, 343, 344, 345, 346, 347, 348, - 349, 350, 351, 352, -1, 354, 355, 356, 357, 358, - 359, 360, 361, 362, 363, 364, 365, 366, -1, 368, - 369, 370, 371, 372, 373, -1, 375, 376, 377, 378, - 379, 380, 381, 382, 383, 384, 385, 386, 387, -1, - 389, 390, 391, 392, 393, 394, 395, -1, 397, 398, - -1, 400, 401, 402, 403, 404, -1, 406, 407, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 421, -1, -1, -1, 425, 426, -1, 428, - 429, 430, 431, 432, 433, 434, 435, -1, 437, 438, - 439, -1, -1, 442, 443, -1, 445, -1, -1, 448, - 449, 450, 451, 452, 453, 454, 455, -1, -1, 458, - 459, 460, 461, -1, 463, 464, 465, 466, -1, 468, - 469, 470, 471, 472, -1, 474, 475, -1, 477, 478, - 479, 480, 481, 482, 483, 484, 485, -1, -1, 488, - -1, -1, 491, 492, 493, 494, 495, 496, 3, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 508, - 509, 510, 511, -1, -1, -1, -1, -1, 23, 24, - 25, 26, 27, 28, 29, 30, -1, 32, 33, 34, - -1, -1, -1, 38, -1, -1, -1, -1, 43, 44, - 45, -1, 47, 48, 49, 50, 51, 52, 53, -1, - 55, 56, 57, 58, -1, 60, 61, 62, 63, 64, - 65, -1, -1, 68, 69, 70, 71, 72, 73, 74, - -1, 76, 77, 78, 79, -1, -1, 82, -1, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, -1, - 95, 96, 97, 98, 99, 100, -1, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, -1, 119, -1, 121, 122, 123, 124, - 125, 126, -1, -1, 129, 130, 131, 132, -1, -1, - 135, 136, 137, 138, 139, -1, 141, 142, 143, -1, - 145, 146, 147, 148, -1, 150, 151, 152, 153, -1, - 155, 156, 157, 158, 159, 160, -1, -1, 163, -1, - 165, 166, 167, 168, -1, 170, -1, 172, 173, -1, - 175, 176, 177, -1, 179, 180, 181, 182, -1, -1, - -1, 186, 187, -1, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 200, -1, 202, 203, 204, - 205, 206, 207, 208, -1, 210, 211, -1, 213, 214, - 215, 216, 217, 218, 219, -1, 221, -1, 223, 224, - 225, 226, 227, 228, 229, 230, -1, 232, 233, 234, - -1, -1, 237, 238, 239, 240, -1, 242, 243, 244, - 245, 246, 247, 248, 249, -1, 251, 252, 253, 254, - 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, -1, -1, 281, 282, 283, 284, - -1, -1, 287, 288, 289, 290, 291, -1, 293, 294, - -1, -1, 297, 298, 299, -1, -1, 302, 303, -1, - 305, 306, 307, -1, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, -1, -1, -1, -1, - 325, 326, -1, 328, 329, 330, -1, 332, 333, 334, - -1, 336, 337, 338, 339, 340, 341, -1, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, -1, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, -1, 368, 369, 370, 371, 372, 373, -1, - 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, -1, 389, 390, 391, 392, 393, 394, - 395, -1, 397, 398, -1, 400, 401, 402, 403, 404, - -1, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, -1, 421, -1, -1, -1, - 425, 426, -1, 428, 429, 430, 431, 432, 433, 434, - 435, -1, 437, 438, 439, -1, -1, 442, 443, -1, - 445, -1, -1, 448, 449, 450, 451, 452, 453, 454, - 455, -1, -1, 458, 459, 460, 461, -1, 463, 464, - 465, 466, -1, 468, 469, 470, 471, 472, -1, 474, - 475, -1, 477, 478, 479, 480, 481, 482, 483, 484, - 485, -1, -1, 488, -1, -1, 491, 492, 493, 494, - 495, 496, 3, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 508, 509, 510, 511, -1, -1, -1, - -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, - -1, 32, 33, 34, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 44, 45, -1, -1, 48, 49, -1, - 51, 52, 53, 54, 55, -1, 57, 58, -1, -1, - 61, 62, 63, 64, 65, -1, -1, 68, 69, 70, - 71, 72, 73, 74, -1, 76, 77, 78, 79, 80, - -1, -1, -1, 84, 85, 86, 87, 88, 89, -1, - 91, 92, 93, -1, 95, 96, 97, 98, 99, 100, - -1, -1, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, -1, 119, -1, - 121, 122, 123, 124, 125, 126, -1, -1, 129, 130, - 131, 132, -1, -1, 135, 136, 137, 138, 139, -1, - 141, 142, 143, -1, 145, 146, 147, 148, -1, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, -1, 165, 166, 167, 168, -1, 170, - -1, 172, -1, -1, -1, 176, 177, 178, -1, 180, - 181, 182, -1, 184, 185, -1, 187, -1, 189, 190, - 191, 192, 193, 194, 195, -1, 197, 198, 199, 200, - -1, 202, 203, 204, 205, 206, 207, 208, -1, 210, - -1, 212, 213, 214, 215, 216, 217, 218, 219, -1, - 221, -1, 223, -1, -1, 226, -1, 228, 229, 230, - -1, 232, 233, 234, -1, -1, 237, -1, 239, -1, - -1, 242, 243, 244, 245, 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, 273, -1, 275, 276, 277, 278, 279, -1, - 281, 282, -1, 284, -1, 286, 287, 288, 289, 290, - 291, -1, 293, 294, -1, -1, 297, 298, 299, -1, - -1, 302, 303, 304, -1, 306, -1, 308, 309, 310, - 311, 312, 313, 314, -1, 316, 317, 318, 319, 320, - -1, -1, -1, -1, 325, 326, 327, -1, 329, 330, - 331, 332, 333, 334, -1, 336, 337, 338, 339, 340, - 341, -1, 343, 344, 345, -1, 347, 348, 349, 350, - 351, 352, -1, 354, 355, 356, 357, 358, 359, 360, - 361, 362, 363, 364, 365, 366, -1, 368, 369, -1, - 371, 372, 373, 374, -1, 376, 377, 378, 379, 380, - 381, 382, 383, 384, 385, 386, 387, -1, -1, 390, - 391, 392, 393, 394, 395, 396, 397, 398, -1, -1, - 401, 402, 403, 404, -1, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 421, 422, -1, -1, 425, 426, -1, 428, -1, 430, - 431, 432, 433, 434, 435, -1, 437, 438, 439, -1, - -1, 442, 443, 444, 445, 446, -1, 448, 449, 450, - 451, 452, 453, 454, 455, -1, -1, 458, 459, 460, - -1, -1, 463, 464, 465, 466, -1, 468, 469, 470, - 471, 472, 473, 474, 475, -1, 477, -1, 479, 480, - 481, 482, 483, 484, 485, -1, -1, 488, -1, -1, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 23, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 33, -1, 35, 36, -1, -1, -1, -1, 23, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, - -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, - 62, -1, -1, -1, -1, -1, -1, -1, -1, 53, - -1, -1, -1, -1, 76, -1, -1, -1, 62, -1, - -1, -1, -1, -1, -1, 87, -1, -1, -1, -1, - -1, -1, 76, -1, -1, -1, -1, 99, -1, 101, - -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, - 112, -1, -1, -1, -1, 99, -1, 101, -1, -1, - -1, -1, -1, -1, -1, 127, 128, -1, 112, -1, - -1, -1, -1, -1, -1, -1, 138, -1, -1, -1, - -1, -1, 144, 127, 128, -1, -1, -1, -1, -1, - -1, 153, -1, -1, 138, -1, -1, -1, -1, -1, - 144, -1, -1, -1, -1, -1, -1, -1, 170, 153, - -1, -1, 174, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 170, -1, -1, -1, - 174, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 418, 419, -1, 421, -1, -1, -1, 425, 426, -1, + 428, 429, 430, 431, 432, 433, 434, 435, -1, 437, + 438, 439, -1, -1, 442, 443, -1, 445, -1, -1, + 448, 449, 450, 451, 452, 453, 454, 455, -1, -1, + 458, 459, 460, 461, -1, 463, 464, 465, 466, -1, + 468, 469, 470, 471, 472, -1, 474, 475, -1, 477, + 478, 479, 480, 481, 482, 483, 484, 485, -1, -1, + 488, -1, -1, 491, 492, 493, 494, 495, 496, 3, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 508, 509, 510, 511, -1, -1, -1, -1, -1, 23, + 24, 25, 26, 27, 28, 29, 30, -1, 32, 33, + 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 44, 45, -1, -1, 48, 49, -1, 51, 52, 53, + 54, 55, -1, 57, 58, -1, -1, 61, 62, 63, + 64, 65, -1, -1, 68, 69, 70, 71, 72, 73, + 74, -1, 76, 77, 78, 79, 80, -1, -1, -1, + 84, 85, 86, 87, 88, 89, -1, 91, 92, 93, + -1, 95, 96, 97, 98, 99, 100, -1, -1, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, -1, 119, -1, 121, 122, 123, + 124, 125, 126, -1, -1, 129, 130, 131, 132, -1, + -1, 135, 136, 137, 138, 139, -1, 141, 142, 143, + -1, 145, 146, 147, 148, -1, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + -1, 165, 166, 167, 168, -1, 170, -1, 172, -1, + -1, -1, 176, 177, 178, -1, 180, 181, 182, -1, + 184, 185, -1, 187, -1, 189, 190, 191, 192, 193, + 194, 195, -1, 197, 198, 199, 200, -1, 202, 203, + 204, 205, 206, 207, 208, -1, 210, -1, 212, 213, + 214, 215, 216, 217, 218, 219, -1, 221, -1, 223, + -1, -1, 226, -1, 228, 229, 230, -1, 232, 233, + 234, -1, -1, 237, -1, 239, -1, -1, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + -1, 275, 276, 277, 278, 279, -1, 281, 282, -1, + 284, -1, 286, 287, 288, 289, 290, 291, -1, 293, + 294, -1, -1, 297, 298, 299, -1, -1, 302, 303, + 304, -1, 306, -1, 308, 309, 310, 311, 312, 313, + 314, -1, 316, 317, 318, 319, 320, -1, -1, -1, + -1, 325, 326, 327, -1, 329, 330, 331, 332, 333, + 334, -1, 336, 337, 338, 339, 340, 341, -1, 343, + 344, 345, -1, 347, 348, 349, 350, 351, 352, -1, + 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, + 364, 365, 366, -1, 368, 369, -1, 371, 372, 373, + 374, -1, 376, 377, 378, 379, 380, 381, 382, 383, + 384, 385, 386, 387, -1, -1, 390, 391, 392, 393, + 394, 395, 396, 397, 398, -1, -1, 401, 402, 403, + 404, -1, 406, 407, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 421, 422, -1, + -1, 425, 426, -1, 428, -1, 430, 431, 432, 433, + 434, 435, -1, 437, 438, 439, -1, -1, 442, 443, + 444, 445, 446, -1, 448, 449, 450, 451, 452, 453, + 454, 455, -1, -1, 458, 459, 460, -1, -1, 463, + 464, 465, 466, -1, 468, 469, 470, 471, 472, 473, + 474, 475, -1, 477, -1, 479, 480, 481, 482, 483, + 484, 485, -1, -1, 488, -1, -1, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, + 504, 505, 506, 507, 508, 509, 510, 511, 23, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, + 35, 36, -1, -1, -1, -1, 23, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 33, -1, 53, -1, + -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, + -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, + -1, 76, -1, -1, -1, 62, -1, -1, -1, -1, + -1, -1, 87, -1, -1, -1, -1, -1, -1, 76, + -1, -1, -1, -1, 99, -1, 101, -1, -1, -1, + 87, -1, -1, -1, -1, -1, -1, 112, -1, -1, + -1, -1, 99, -1, 101, -1, -1, -1, -1, -1, + -1, -1, 127, 128, -1, 112, -1, -1, -1, -1, + -1, -1, -1, 138, -1, -1, -1, -1, -1, 144, + 127, 128, -1, -1, -1, -1, -1, -1, 153, -1, + -1, 138, -1, -1, -1, -1, -1, 144, -1, -1, + -1, -1, -1, -1, -1, 170, 153, -1, -1, 174, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 216, -1, -1, -1, -1, -1, + -1, -1, -1, 170, -1, -1, -1, 174, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 216, -1, -1, -1, -1, -1, -1, -1, - -1, 243, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 243, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 216, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 216, + -1, -1, -1, -1, -1, -1, -1, -1, 243, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 243, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 321, - 322, 323, -1, -1, -1, -1, -1, 329, -1, -1, - 332, -1, -1, -1, -1, -1, -1, 321, 322, 323, - -1, -1, -1, -1, -1, 329, -1, -1, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 363, -1, -1, -1, -1, -1, -1, -1, -1, - 372, -1, -1, -1, -1, -1, -1, -1, -1, 363, - -1, -1, -1, -1, -1, -1, 388, -1, 372, -1, - -1, -1, -1, 395, -1, -1, -1, 399, -1, -1, - -1, -1, -1, -1, 388, -1, -1, -1, -1, 411, - -1, 395, -1, -1, -1, 399, -1, -1, -1, -1, - -1, 423, -1, -1, -1, 427, -1, 411, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 423, - -1, -1, -1, 427, -1, -1, 448, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 462, -1, -1, -1, 448, -1, 468, -1, -1, -1, - -1, 473, -1, -1, -1, -1, 478, -1, 462, -1, - -1, -1, -1, -1, 468, -1, -1, -1, 490, 473, + -1, -1, -1, -1, -1, -1, 321, 322, 323, -1, + -1, -1, -1, -1, 329, -1, -1, 332, -1, -1, + -1, -1, -1, -1, 321, 322, 323, -1, -1, -1, + -1, -1, 329, -1, -1, 332, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, + -1, -1, -1, -1, -1, -1, -1, 372, -1, -1, + -1, -1, -1, -1, -1, -1, 363, -1, -1, -1, + -1, -1, -1, 388, -1, 372, -1, -1, -1, -1, + 395, -1, -1, -1, 399, -1, -1, -1, -1, -1, + -1, 388, -1, -1, -1, -1, 411, -1, 395, -1, + -1, -1, 399, -1, -1, -1, -1, -1, 423, -1, + -1, -1, 427, -1, 411, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 423, -1, -1, -1, + 427, -1, -1, 448, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 462, -1, -1, + -1, 448, -1, 468, -1, -1, -1, -1, 473, -1, + -1, -1, -1, 478, -1, 462, -1, -1, -1, -1, + -1, 468, -1, -1, -1, 490, 473, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 490, -1, -1, -1, - -1, -1, 514, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 528, -1, -1, -1, - 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 528 + -1, -1, -1, 490, -1, -1, -1, -1, -1, 514, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 528, -1, -1, -1, 514, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 528 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -20053,12 +20210,12 @@ static const yytype_uint16 yystos[] = 332, 363, 372, 388, 395, 399, 411, 423, 427, 448, 462, 465, 468, 473, 490, 514, 528, 539, 540, 541, 542, 557, 566, 568, 573, 589, 593, 594, 596, 603, - 604, 608, 615, 616, 618, 621, 622, 672, 678, 689, - 700, 701, 714, 715, 716, 717, 719, 721, 722, 726, - 786, 787, 967, 970, 973, 980, 981, 983, 986, 987, - 988, 995, 999, 1005, 1006, 1009, 1014, 1018, 1019, 1020, - 1027, 1030, 1031, 1032, 1035, 1036, 1038, 442, 493, 619, - 109, 205, 379, 390, 427, 480, 109, 194, 300, 1021, + 604, 608, 615, 616, 618, 621, 622, 674, 680, 691, + 702, 703, 716, 717, 718, 719, 721, 723, 724, 728, + 788, 789, 969, 972, 975, 982, 983, 985, 988, 989, + 990, 997, 1001, 1007, 1008, 1011, 1016, 1020, 1021, 1022, + 1029, 1032, 1033, 1034, 1037, 1038, 1040, 442, 493, 619, + 109, 205, 379, 390, 427, 480, 109, 194, 300, 1023, 619, 3, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 62, @@ -20100,10 +20257,10 @@ static const yytype_uint16 yystos[] = 475, 477, 478, 479, 480, 481, 482, 483, 484, 485, 488, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 559, 868, 956, 960, 1041, 1042, 1043, 3, - 178, 250, 420, 559, 982, 1041, 295, 619, 56, 174, - 528, 711, 180, 244, 300, 320, 379, 432, 434, 457, - 460, 598, 670, 979, 5, 31, 332, 559, 560, 955, + 510, 511, 559, 870, 958, 962, 1043, 1044, 1045, 3, + 178, 250, 420, 559, 984, 1043, 295, 619, 56, 174, + 528, 713, 180, 244, 300, 320, 379, 432, 434, 457, + 460, 598, 672, 981, 5, 31, 332, 559, 560, 957, 3, 31, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46, 47, 50, 54, 55, 56, 57, 58, 59, 60, 66, 67, 72, 73, 75, 80, 81, 82, 83, @@ -20120,315 +20277,318 @@ static const yytype_uint16 yystos[] = 439, 440, 441, 444, 446, 447, 450, 456, 457, 461, 462, 467, 473, 474, 476, 478, 486, 487, 489, 490, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, - 507, 565, 1041, 1045, 1047, 25, 82, 98, 148, 158, + 507, 565, 1043, 1047, 1049, 25, 82, 98, 148, 158, 171, 176, 205, 249, 254, 326, 341, 376, 379, 390, - 393, 413, 427, 434, 435, 445, 451, 480, 598, 673, - 674, 677, 619, 955, 33, 101, 138, 478, 528, 542, + 393, 413, 427, 434, 435, 445, 451, 480, 598, 675, + 676, 679, 619, 957, 33, 101, 138, 478, 528, 542, 557, 566, 568, 589, 593, 594, 603, 604, 608, 618, - 622, 672, 678, 689, 700, 701, 714, 967, 970, 973, - 980, 981, 991, 995, 999, 1005, 1009, 1014, 1027, 1030, - 1035, 1036, 1038, 109, 76, 67, 80, 82, 161, 235, + 622, 674, 680, 691, 702, 703, 716, 969, 972, 975, + 982, 983, 993, 997, 1001, 1007, 1011, 1016, 1029, 1032, + 1037, 1038, 1040, 109, 76, 67, 80, 82, 161, 235, 286, 296, 308, 327, 375, 422, 444, 446, 450, 473, - 528, 558, 559, 560, 715, 787, 789, 791, 792, 802, - 809, 810, 868, 870, 871, 109, 5, 559, 561, 1007, - 559, 955, 31, 180, 244, 394, 438, 442, 475, 559, - 1028, 1029, 1034, 619, 31, 133, 738, 739, 180, 244, - 379, 394, 438, 475, 1000, 1001, 1034, 619, 558, 559, - 560, 714, 726, 809, 427, 735, 558, 175, 528, 1011, - 528, 351, 727, 728, 955, 727, 715, 716, 1030, 0, - 531, 123, 215, 256, 464, 149, 220, 301, 456, 741, - 742, 792, 792, 715, 717, 719, 532, 478, 989, 216, - 31, 428, 438, 442, 558, 714, 194, 559, 194, 558, - 955, 194, 558, 194, 809, 194, 558, 280, 361, 561, + 528, 558, 559, 560, 717, 789, 791, 793, 794, 804, + 811, 812, 870, 872, 873, 109, 5, 559, 561, 1009, + 559, 957, 31, 180, 244, 394, 438, 442, 475, 559, + 1030, 1031, 1036, 619, 31, 133, 740, 741, 180, 244, + 379, 394, 438, 475, 1002, 1003, 1036, 619, 558, 559, + 560, 716, 728, 811, 427, 737, 558, 175, 528, 1013, + 528, 351, 729, 730, 957, 729, 717, 718, 1032, 0, + 531, 123, 215, 256, 464, 149, 220, 301, 456, 743, + 744, 794, 794, 717, 719, 721, 532, 478, 991, 216, + 31, 428, 438, 442, 558, 716, 194, 559, 194, 558, + 957, 194, 558, 194, 811, 194, 558, 280, 361, 561, 347, 620, 526, 530, 562, 563, 528, 83, 109, 176, - 205, 249, 379, 390, 427, 451, 480, 985, 109, 714, + 205, 249, 379, 390, 427, 451, 480, 987, 109, 716, 558, 432, 434, 432, 434, 361, 194, 558, 386, 176, - 249, 351, 390, 427, 451, 480, 696, 205, 31, 955, + 249, 351, 390, 427, 451, 480, 698, 205, 31, 957, 194, 565, 257, 445, 108, 427, 427, 480, 383, 386, - 194, 559, 675, 962, 194, 952, 955, 194, 955, 528, - 607, 300, 434, 991, 3, 473, 992, 994, 995, 997, - 998, 1041, 1045, 989, 559, 561, 982, 528, 528, 169, - 528, 715, 810, 528, 528, 558, 528, 528, 174, 528, - 528, 528, 528, 715, 787, 792, 802, 521, 562, 19, - 41, 559, 803, 804, 803, 388, 532, 718, 528, 715, - 809, 810, 38, 43, 102, 175, 211, 227, 238, 274, - 321, 328, 370, 389, 462, 806, 804, 41, 559, 803, - 805, 514, 814, 561, 517, 528, 528, 968, 1029, 1029, - 1029, 511, 226, 1029, 530, 295, 4, 6, 7, 8, + 194, 559, 677, 964, 194, 954, 957, 194, 957, 528, + 607, 300, 434, 993, 3, 473, 994, 996, 997, 999, + 1000, 1043, 1047, 991, 559, 561, 984, 528, 528, 169, + 528, 717, 812, 528, 528, 558, 528, 528, 174, 528, + 528, 528, 528, 717, 789, 794, 804, 521, 562, 19, + 41, 559, 805, 806, 805, 388, 532, 720, 528, 717, + 811, 812, 38, 43, 102, 175, 211, 227, 238, 274, + 321, 328, 370, 389, 462, 808, 806, 41, 559, 805, + 807, 514, 816, 561, 517, 528, 528, 970, 1031, 1031, + 1031, 511, 226, 1031, 530, 295, 4, 6, 7, 8, 9, 10, 40, 55, 57, 58, 66, 72, 73, 84, 113, 116, 118, 137, 154, 162, 167, 184, 185, 218, 219, 221, 231, 250, 273, 275, 280, 285, 288, 297, 348, 374, 403, 438, 439, 447, 461, 474, 512, 519, 520, 521, 526, 528, 533, 534, 535, 536, 559, 561, - 715, 776, 826, 829, 832, 833, 834, 836, 837, 838, - 839, 841, 842, 858, 860, 861, 862, 863, 864, 865, - 866, 867, 868, 869, 871, 872, 887, 888, 899, 921, - 927, 935, 936, 937, 956, 957, 958, 934, 936, 1000, - 1000, 561, 1000, 511, 1000, 174, 440, 517, 620, 562, - 809, 1015, 3, 173, 175, 478, 995, 1010, 1012, 173, - 1013, 559, 858, 905, 906, 727, 532, 528, 964, 529, - 529, 529, 541, 174, 300, 576, 222, 159, 1015, 31, - 133, 736, 736, 60, 736, 164, 169, 241, 292, 747, - 749, 750, 779, 781, 782, 783, 183, 295, 467, 295, - 741, 742, 528, 558, 1007, 428, 1033, 174, 511, 226, + 717, 778, 828, 831, 834, 835, 836, 838, 839, 840, + 841, 843, 844, 860, 862, 863, 864, 865, 866, 867, + 868, 869, 870, 871, 873, 874, 889, 890, 901, 923, + 929, 937, 938, 939, 958, 959, 960, 936, 938, 1002, + 1002, 561, 1002, 511, 1002, 174, 440, 517, 620, 562, + 811, 1017, 3, 173, 175, 478, 997, 1012, 1014, 173, + 1015, 559, 860, 907, 908, 729, 532, 528, 966, 529, + 529, 529, 541, 174, 300, 576, 222, 159, 1017, 31, + 133, 738, 738, 60, 738, 164, 169, 241, 292, 749, + 751, 752, 781, 783, 784, 785, 183, 295, 467, 295, + 743, 744, 528, 558, 1009, 428, 1035, 174, 511, 226, 154, 359, 154, 27, 33, 138, 299, 359, 363, 395, 470, 551, 554, 555, 359, 154, 41, 61, 107, 204, 255, 266, 278, 310, 359, 365, 390, 395, 411, 554, 609, 612, 154, 359, 395, 554, 154, 359, 395, 554, - 154, 1021, 41, 1022, 296, 495, 858, 928, 564, 565, + 154, 1023, 41, 1024, 296, 495, 860, 930, 564, 565, 563, 3, 31, 38, 43, 47, 50, 56, 60, 82, 84, 90, 102, 133, 173, 175, 178, 179, 196, 211, 224, 225, 227, 238, 240, 250, 274, 283, 305, 307, 328, 370, 389, 400, 420, 429, 450, 461, 476, 478, - 529, 742, 858, 908, 909, 959, 965, 1041, 1046, 858, - 427, 558, 559, 529, 528, 659, 379, 598, 670, 280, - 971, 194, 559, 597, 480, 194, 558, 194, 558, 1040, - 194, 558, 194, 558, 194, 558, 90, 976, 154, 494, - 91, 130, 313, 433, 194, 559, 154, 530, 963, 64, - 366, 532, 676, 154, 532, 676, 154, 295, 605, 606, - 858, 965, 361, 529, 532, 4, 162, 295, 447, 519, - 520, 561, 611, 614, 958, 990, 992, 993, 996, 991, - 440, 528, 708, 710, 858, 906, 528, 3, 69, 70, + 529, 744, 860, 910, 911, 961, 967, 1043, 1048, 860, + 427, 558, 559, 529, 528, 661, 379, 598, 672, 280, + 973, 194, 559, 597, 480, 194, 558, 194, 558, 1042, + 194, 558, 194, 558, 194, 558, 90, 978, 154, 494, + 91, 130, 313, 433, 194, 559, 154, 530, 965, 64, + 366, 532, 678, 154, 532, 678, 154, 295, 605, 606, + 860, 967, 361, 529, 532, 4, 162, 295, 447, 519, + 520, 561, 611, 614, 960, 992, 994, 995, 998, 993, + 440, 528, 710, 712, 860, 908, 528, 3, 69, 70, 110, 111, 114, 115, 191, 192, 258, 259, 260, 261, 262, 263, 264, 265, 268, 269, 343, 344, 384, 385, - 484, 485, 508, 509, 561, 844, 845, 846, 847, 848, - 849, 850, 851, 852, 853, 854, 855, 856, 911, 912, - 804, 805, 858, 558, 858, 913, 519, 520, 559, 859, - 860, 888, 899, 915, 528, 858, 905, 916, 858, 59, - 174, 236, 441, 858, 906, 919, 858, 529, 560, 528, - 429, 756, 757, 757, 738, 739, 792, 222, 733, 802, - 757, 47, 761, 757, 227, 38, 227, 389, 806, 227, - 305, 807, 792, 807, 227, 806, 528, 227, 807, 227, - 150, 202, 794, 227, 761, 528, 560, 528, 757, 302, - 858, 1002, 1004, 908, 3, 38, 43, 47, 50, 55, + 484, 485, 508, 509, 561, 846, 847, 848, 849, 850, + 851, 852, 853, 854, 855, 856, 857, 858, 913, 914, + 806, 807, 860, 558, 860, 915, 519, 520, 559, 861, + 862, 890, 901, 917, 528, 860, 907, 918, 860, 59, + 174, 236, 441, 860, 908, 921, 860, 529, 560, 528, + 429, 758, 759, 759, 740, 741, 794, 222, 735, 804, + 759, 47, 763, 759, 227, 38, 227, 389, 808, 227, + 305, 809, 794, 809, 227, 808, 528, 227, 809, 227, + 150, 202, 796, 227, 763, 528, 560, 528, 759, 302, + 860, 1004, 1006, 910, 3, 38, 43, 47, 50, 55, 56, 57, 58, 60, 72, 73, 82, 84, 90, 102, 113, 116, 167, 173, 175, 179, 196, 211, 218, 219, 221, 224, 225, 227, 238, 240, 250, 273, 274, 275, 283, 288, 305, 307, 328, 348, 370, 374, 389, 396, 400, 403, 420, 429, 438, 439, 450, 456, 461, 474, - 478, 820, 822, 823, 825, 827, 829, 831, 833, 834, - 835, 837, 838, 841, 842, 910, 961, 1041, 1044, 41, - 239, 559, 528, 526, 715, 477, 840, 858, 925, 840, - 840, 528, 528, 828, 828, 331, 715, 528, 830, 952, - 536, 72, 73, 840, 858, 828, 528, 528, 492, 514, - 528, 843, 528, 843, 528, 858, 858, 858, 84, 150, - 938, 942, 858, 906, 907, 715, 858, 905, 565, 9, - 560, 889, 890, 891, 19, 530, 562, 929, 562, 528, - 561, 528, 528, 561, 958, 3, 8, 11, 15, 16, + 478, 822, 824, 825, 827, 829, 831, 833, 835, 836, + 837, 839, 840, 843, 844, 912, 963, 1043, 1046, 41, + 239, 559, 528, 526, 717, 477, 842, 860, 927, 842, + 842, 528, 528, 830, 830, 331, 717, 528, 832, 954, + 536, 72, 73, 842, 860, 830, 528, 528, 492, 514, + 528, 845, 528, 845, 528, 860, 860, 860, 84, 150, + 940, 944, 860, 908, 909, 717, 860, 907, 565, 9, + 560, 891, 892, 893, 19, 530, 562, 931, 562, 528, + 561, 528, 528, 561, 960, 3, 8, 11, 15, 16, 17, 18, 20, 21, 22, 37, 41, 47, 54, 81, 179, 196, 201, 224, 225, 240, 280, 283, 297, 300, 400, 512, 515, 516, 517, 519, 520, 521, 522, 523, - 524, 897, 898, 899, 901, 932, 491, 873, 307, 858, - 532, 733, 528, 561, 733, 3, 118, 244, 561, 611, - 842, 1003, 105, 1004, 1004, 41, 559, 529, 532, 989, - 532, 529, 728, 952, 953, 467, 729, 1015, 195, 361, - 222, 1015, 659, 395, 717, 717, 31, 743, 744, 858, - 60, 717, 737, 166, 277, 767, 229, 278, 347, 398, - 464, 4, 9, 31, 762, 858, 519, 520, 763, 764, - 858, 860, 779, 780, 750, 749, 747, 748, 169, 782, - 290, 784, 60, 723, 724, 725, 795, 859, 936, 936, - 747, 779, 906, 964, 174, 479, 1008, 558, 239, 559, + 524, 899, 900, 901, 903, 934, 491, 875, 307, 860, + 532, 735, 528, 561, 735, 3, 118, 244, 561, 611, + 844, 1005, 105, 1006, 1006, 41, 559, 529, 532, 991, + 532, 529, 730, 954, 955, 467, 731, 1017, 195, 361, + 222, 1017, 661, 395, 719, 719, 31, 745, 746, 860, + 60, 719, 739, 166, 277, 769, 229, 278, 347, 398, + 464, 4, 9, 31, 764, 860, 519, 520, 765, 766, + 860, 862, 781, 782, 752, 751, 749, 750, 169, 784, + 290, 786, 60, 725, 726, 727, 797, 861, 938, 938, + 749, 781, 908, 966, 174, 479, 1010, 558, 239, 559, 440, 558, 75, 83, 94, 171, 194, 335, 457, 549, - 550, 559, 639, 666, 83, 94, 567, 94, 567, 528, + 550, 559, 639, 668, 83, 94, 567, 94, 567, 528, 440, 316, 406, 528, 637, 248, 316, 406, 460, 637, - 94, 532, 440, 558, 3, 825, 611, 60, 613, 611, + 94, 532, 440, 558, 3, 827, 611, 60, 613, 611, 611, 107, 255, 266, 60, 440, 490, 514, 610, 271, - 379, 610, 612, 809, 94, 440, 567, 379, 558, 440, - 379, 1021, 561, 559, 528, 1026, 527, 19, 908, 908, - 909, 195, 364, 740, 532, 741, 742, 13, 14, 224, - 224, 440, 440, 559, 658, 663, 490, 709, 558, 386, - 351, 390, 427, 451, 480, 696, 154, 101, 594, 622, - 972, 973, 1036, 280, 201, 599, 558, 280, 595, 609, - 280, 528, 659, 41, 280, 41, 280, 659, 280, 528, - 690, 691, 692, 693, 694, 695, 697, 194, 559, 653, - 977, 565, 154, 174, 617, 675, 564, 530, 962, 952, - 955, 955, 962, 529, 532, 13, 991, 997, 4, 958, - 4, 958, 561, 565, 1024, 1025, 56, 103, 124, 142, - 147, 170, 173, 189, 285, 293, 315, 345, 712, 41, - 529, 858, 529, 174, 532, 529, 324, 914, 529, 859, - 859, 11, 15, 16, 20, 21, 22, 201, 224, 297, - 515, 516, 517, 519, 520, 521, 522, 523, 524, 899, - 859, 529, 811, 812, 870, 169, 174, 917, 918, 532, - 529, 41, 919, 906, 919, 919, 174, 529, 41, 803, - 528, 953, 4, 9, 559, 751, 752, 754, 755, 863, - 936, 934, 180, 244, 427, 432, 434, 460, 558, 734, - 487, 815, 529, 528, 757, 792, 792, 227, 792, 295, - 467, 808, 792, 227, 936, 792, 792, 287, 287, 528, - 792, 757, 560, 816, 817, 528, 560, 816, 532, 529, - 532, 530, 528, 825, 528, 528, 530, 824, 40, 824, - 528, 844, 845, 846, 847, 848, 849, 850, 851, 852, - 853, 854, 855, 856, 857, 529, 532, 828, 568, 573, - 700, 701, 714, 969, 1014, 1030, 906, 907, 528, 486, - 922, 923, 858, 907, 958, 19, 858, 892, 893, 894, - 895, 840, 840, 8, 15, 16, 20, 21, 22, 515, - 516, 517, 519, 520, 521, 522, 523, 524, 559, 897, - 902, 529, 906, 438, 438, 958, 958, 858, 528, 528, - 560, 939, 361, 946, 169, 527, 529, 532, 19, 532, - 537, 858, 521, 563, 906, 958, 858, 857, 857, 822, - 858, 858, 858, 858, 858, 858, 858, 858, 5, 565, - 966, 438, 46, 424, 933, 962, 858, 858, 528, 715, - 864, 920, 927, 133, 162, 280, 285, 290, 447, 458, - 858, 285, 528, 858, 440, 54, 179, 196, 201, 240, - 400, 858, 858, 858, 858, 858, 858, 858, 858, 858, - 858, 31, 39, 405, 896, 526, 530, 931, 183, 165, - 874, 374, 528, 888, 937, 174, 788, 908, 788, 528, - 561, 559, 558, 1010, 558, 1018, 858, 532, 529, 229, - 41, 467, 1017, 558, 570, 467, 528, 559, 575, 585, - 586, 588, 42, 127, 745, 532, 467, 745, 271, 717, - 374, 375, 519, 520, 764, 766, 860, 398, 229, 296, - 319, 319, 532, 523, 4, 765, 958, 765, 374, 375, - 766, 558, 951, 284, 402, 785, 528, 953, 954, 532, - 183, 467, 201, 183, 222, 780, 748, 529, 559, 561, - 559, 561, 359, 559, 359, 554, 528, 194, 550, 955, - 229, 280, 229, 467, 528, 642, 649, 650, 821, 822, - 530, 547, 548, 955, 559, 194, 955, 194, 549, 27, - 138, 395, 546, 553, 565, 633, 647, 955, 60, 60, - 565, 641, 662, 60, 60, 955, 551, 955, 359, 395, - 554, 609, 611, 962, 955, 611, 962, 955, 611, 359, - 395, 554, 955, 955, 549, 955, 359, 395, 554, 955, - 955, 561, 1022, 1025, 520, 858, 928, 741, 741, 741, - 287, 287, 529, 476, 909, 740, 858, 858, 285, 561, - 984, 285, 984, 559, 340, 707, 529, 532, 293, 174, - 440, 703, 971, 597, 480, 558, 558, 1040, 558, 558, - 558, 558, 300, 670, 154, 3, 528, 528, 154, 154, - 240, 559, 639, 651, 654, 657, 667, 669, 490, 492, - 644, 153, 714, 154, 145, 590, 822, 154, 490, 978, - 154, 3, 43, 47, 50, 56, 82, 84, 90, 102, - 173, 175, 178, 179, 196, 211, 224, 225, 227, 238, - 240, 250, 274, 283, 305, 307, 328, 370, 400, 420, - 429, 450, 461, 478, 529, 698, 699, 965, 1041, 532, - 532, 41, 280, 295, 559, 3, 676, 564, 676, 295, - 676, 605, 858, 708, 858, 1023, 529, 532, 41, 706, - 561, 706, 280, 285, 345, 706, 60, 706, 822, 529, - 858, 858, 858, 917, 822, 859, 859, 859, 859, 859, - 859, 133, 280, 290, 859, 859, 859, 859, 859, 859, - 859, 859, 859, 859, 529, 532, 41, 813, 858, 858, - 918, 917, 822, 529, 529, 529, 906, 822, 953, 529, - 319, 375, 523, 528, 528, 733, 432, 434, 432, 434, - 558, 735, 735, 735, 858, 183, 768, 439, 479, 759, - 760, 808, 808, 792, 858, 528, 792, 169, 808, 528, - 560, 799, 808, 822, 529, 532, 816, 529, 1002, 3, - 910, 40, 824, 559, 819, 819, 3, 526, 526, 958, - 440, 440, 440, 440, 822, 464, 529, 527, 906, 858, - 140, 923, 924, 529, 529, 529, 858, 19, 532, 537, - 530, 529, 529, 511, 511, 529, 529, 529, 858, 939, - 940, 941, 530, 528, 858, 943, 359, 950, 952, 858, - 858, 889, 942, 529, 529, 529, 511, 859, 859, 147, - 906, 174, 133, 162, 285, 290, 447, 458, 528, 147, - 902, 858, 424, 933, 858, 920, 858, 440, 528, 715, - 858, 928, 564, 528, 528, 157, 875, 789, 790, 815, - 741, 815, 958, 857, 964, 964, 528, 254, 280, 732, - 790, 487, 1016, 41, 60, 571, 792, 581, 588, 929, - 532, 788, 517, 513, 746, 744, 297, 897, 900, 746, - 4, 958, 766, 296, 464, 763, 532, 247, 953, 723, - 60, 936, 528, 560, 60, 271, 1008, 1008, 440, 440, - 858, 280, 666, 528, 154, 528, 642, 205, 663, 664, - 623, 41, 178, 632, 660, 564, 548, 623, 27, 138, - 363, 365, 395, 543, 544, 545, 555, 556, 154, 676, - 154, 676, 633, 647, 633, 529, 532, 561, 626, 517, - 530, 529, 532, 528, 528, 440, 379, 94, 440, 567, - 379, 440, 440, 440, 379, 1022, 1026, 529, 19, 19, - 527, 740, 740, 740, 909, 529, 528, 702, 3, 414, - 415, 528, 561, 713, 863, 658, 707, 599, 558, 595, - 528, 41, 41, 659, 693, 695, 971, 361, 427, 597, - 565, 601, 602, 663, 558, 558, 1040, 558, 649, 650, - 529, 532, 293, 637, 293, 295, 636, 955, 490, 1039, - 558, 528, 715, 558, 637, 41, 558, 529, 532, 821, - 822, 691, 697, 694, 697, 427, 858, 154, 558, 617, - 962, 1024, 561, 561, 285, 663, 521, 663, 561, 521, - 663, 561, 529, 529, 918, 174, 133, 290, 528, 814, - 811, 528, 529, 529, 529, 559, 752, 815, 735, 735, - 735, 735, 558, 558, 558, 60, 188, 777, 14, 529, - 808, 953, 528, 796, 797, 798, 861, 864, 953, 169, - 81, 818, 817, 529, 529, 526, 822, 529, 532, 529, - 527, 958, 958, 529, 845, 847, 848, 849, 848, 849, - 849, 529, 436, 858, 144, 858, 892, 902, 843, 843, - 529, 532, 529, 560, 858, 943, 944, 945, 41, 528, - 939, 947, 201, 529, 946, 857, 858, 37, 37, 858, - 529, 858, 174, 528, 910, 858, 529, 147, 859, 859, - 147, 147, 858, 858, 527, 19, 528, 930, 742, 487, - 858, 306, 879, 532, 768, 740, 768, 529, 559, 730, - 731, 926, 254, 528, 858, 367, 579, 559, 271, 327, - 118, 309, 528, 569, 714, 808, 529, 532, 575, 1016, - 858, 166, 234, 528, 746, 296, 558, 529, 954, 183, - 715, 716, 936, 954, 955, 559, 955, 529, 154, 664, - 550, 664, 623, 653, 532, 529, 120, 209, 278, 280, - 648, 528, 34, 60, 671, 660, 75, 81, 94, 118, - 120, 209, 280, 285, 335, 353, 457, 467, 628, 629, - 643, 178, 118, 193, 280, 637, 610, 108, 118, 178, - 280, 413, 416, 612, 637, 395, 545, 451, 955, 549, - 553, 3, 38, 43, 47, 50, 56, 60, 82, 84, - 90, 102, 173, 175, 179, 196, 211, 224, 225, 227, - 238, 240, 250, 274, 279, 283, 297, 305, 307, 328, - 370, 389, 396, 400, 420, 429, 450, 456, 461, 478, - 519, 520, 561, 611, 624, 665, 822, 900, 959, 1041, - 1047, 565, 662, 906, 743, 955, 955, 955, 955, 549, - 955, 955, 955, 955, 955, 1026, 928, 928, 529, 529, - 529, 741, 108, 379, 530, 858, 610, 713, 528, 528, - 657, 714, 590, 978, 670, 194, 558, 599, 600, 858, - 529, 532, 529, 595, 528, 41, 646, 644, 559, 654, - 87, 607, 108, 278, 41, 561, 591, 592, 659, 714, - 693, 695, 529, 699, 13, 14, 41, 41, 715, 716, - 653, 467, 975, 676, 663, 859, 174, 528, 910, 816, - 529, 532, 529, 768, 558, 558, 558, 558, 31, 104, - 184, 373, 528, 769, 770, 771, 772, 773, 774, 775, - 858, 858, 489, 876, 858, 529, 860, 903, 904, 201, - 183, 793, 797, 529, 799, 800, 801, 962, 824, 958, - 824, 559, 824, 527, 527, 858, 939, 532, 529, 559, - 947, 948, 949, 41, 858, 860, 950, 858, 858, 858, - 910, 529, 858, 37, 37, 858, 858, 147, 529, 520, - 928, 529, 908, 529, 858, 529, 528, 559, 880, 777, - 529, 777, 561, 529, 532, 969, 935, 473, 426, 466, - 580, 559, 574, 584, 295, 577, 486, 684, 686, 687, - 688, 517, 588, 579, 902, 60, 529, 529, 472, 473, - 720, 623, 550, 529, 529, 490, 656, 121, 197, 207, - 120, 469, 858, 118, 41, 528, 962, 955, 859, 121, - 197, 120, 285, 229, 558, 656, 89, 671, 194, 285, - 611, 858, 671, 285, 519, 520, 614, 559, 821, 676, - 676, 3, 959, 963, 517, 529, 529, 440, 440, 527, - 527, 740, 529, 529, 559, 529, 708, 467, 704, 705, - 602, 663, 529, 1039, 41, 427, 280, 528, 528, 601, - 978, 657, 153, 714, 151, 203, 636, 123, 138, 334, - 1039, 108, 590, 529, 532, 978, 490, 1037, 858, 858, - 427, 295, 559, 974, 528, 859, 910, 529, 529, 9, - 360, 758, 777, 528, 397, 528, 529, 532, 559, 877, - 878, 342, 778, 532, 529, 528, 560, 60, 529, 201, - 529, 800, 527, 822, 943, 532, 529, 559, 527, 194, - 529, 858, 858, 858, 19, 19, 527, 529, 529, 559, - 881, 876, 561, 876, 926, 529, 532, 472, 929, 529, - 532, 92, 579, 253, 280, 688, 579, 858, 529, 954, - 954, 353, 656, 528, 645, 623, 529, 193, 528, 858, - 280, 629, 656, 659, 955, 41, 154, 818, 963, 523, - 624, 955, 955, 529, 610, 125, 529, 529, 644, 714, - 558, 154, 602, 41, 529, 955, 1039, 31, 86, 95, - 119, 193, 206, 413, 416, 640, 640, 375, 375, 561, - 41, 65, 75, 244, 715, 558, 528, 559, 578, 587, - 870, 529, 529, 528, 876, 906, 528, 906, 771, 41, - 532, 858, 467, 753, 860, 936, 953, 804, 528, 804, - 947, 858, 928, 928, 315, 882, 778, 778, 714, 309, - 714, 574, 295, 528, 572, 37, 679, 253, 558, 623, - 565, 652, 655, 417, 482, 630, 631, 528, 625, 858, - 529, 252, 668, 193, 467, 552, 523, 451, 708, 561, - 978, 636, 1037, 528, 558, 529, 714, 644, 607, 714, - 75, 298, 75, 975, 858, 81, 582, 529, 532, 582, - 9, 778, 529, 770, 529, 880, 878, 377, 529, 936, - 527, 527, 527, 60, 741, 753, 753, 580, 94, 587, - 134, 858, 436, 60, 685, 659, 517, 529, 532, 609, - 529, 278, 638, 175, 314, 401, 295, 634, 635, 661, - 625, 858, 451, 41, 528, 1037, 636, 1039, 1037, 298, - 298, 528, 529, 962, 583, 962, 978, 578, 583, 529, - 753, 529, 755, 529, 905, 186, 346, 375, 883, 472, - 955, 529, 281, 464, 123, 134, 146, 215, 464, 682, - 407, 431, 679, 668, 624, 655, 529, 631, 207, 123, - 464, 295, 661, 295, 634, 714, 587, 582, 745, 815, - 745, 54, 105, 453, 858, 884, 885, 884, 884, 529, - 714, 815, 395, 281, 683, 858, 118, 528, 571, 680, - 395, 571, 436, 635, 64, 278, 366, 395, 627, 627, - 1037, 529, 583, 746, 746, 885, 374, 168, 330, 168, - 330, 150, 886, 886, 886, 586, 473, 584, 521, 681, - 473, 521, 586, 682, 623, 26, 118, 285, 978, 745, - 37, 105, 183, 278, 437, 815, 529, 528, 815, 746, - 885, 374, 303, 906, 529 + 379, 610, 612, 811, 94, 440, 567, 379, 558, 440, + 379, 1023, 561, 559, 528, 1028, 527, 19, 910, 910, + 911, 195, 364, 742, 532, 743, 744, 13, 14, 224, + 224, 440, 440, 559, 660, 665, 490, 711, 558, 386, + 351, 390, 427, 451, 480, 698, 154, 101, 594, 622, + 974, 975, 1038, 280, 201, 599, 558, 280, 595, 609, + 280, 528, 661, 41, 280, 41, 280, 661, 280, 528, + 692, 693, 694, 695, 696, 697, 699, 194, 559, 655, + 979, 565, 154, 174, 617, 677, 564, 530, 964, 954, + 957, 957, 964, 529, 532, 13, 993, 999, 4, 960, + 4, 960, 561, 565, 1026, 1027, 56, 103, 124, 142, + 147, 170, 173, 189, 285, 293, 315, 345, 714, 41, + 529, 860, 529, 174, 532, 529, 324, 916, 529, 861, + 861, 11, 15, 16, 20, 21, 22, 201, 224, 297, + 515, 516, 517, 519, 520, 521, 522, 523, 524, 901, + 861, 529, 813, 814, 872, 169, 174, 919, 920, 532, + 529, 41, 921, 908, 921, 921, 174, 529, 41, 805, + 528, 955, 4, 9, 559, 753, 754, 756, 757, 865, + 938, 936, 180, 244, 427, 432, 434, 460, 558, 736, + 487, 817, 529, 528, 759, 794, 794, 227, 794, 295, + 467, 810, 794, 227, 938, 794, 794, 287, 287, 528, + 794, 759, 560, 818, 819, 528, 560, 818, 532, 529, + 532, 530, 528, 825, 827, 528, 528, 40, 530, 826, + 40, 826, 528, 846, 847, 848, 849, 850, 851, 852, + 853, 854, 855, 856, 857, 858, 859, 529, 532, 830, + 568, 573, 702, 703, 716, 971, 1016, 1032, 908, 909, + 528, 486, 924, 925, 860, 909, 960, 19, 860, 894, + 895, 896, 897, 842, 842, 8, 15, 16, 20, 21, + 22, 515, 516, 517, 519, 520, 521, 522, 523, 524, + 559, 899, 904, 529, 908, 438, 438, 960, 960, 860, + 528, 528, 560, 941, 361, 948, 169, 527, 529, 532, + 19, 532, 537, 860, 521, 563, 908, 960, 860, 859, + 859, 824, 860, 860, 860, 860, 860, 860, 860, 860, + 5, 565, 968, 438, 46, 424, 935, 964, 860, 860, + 528, 717, 866, 922, 929, 133, 162, 280, 285, 290, + 447, 458, 860, 285, 528, 860, 440, 54, 179, 196, + 201, 240, 400, 860, 860, 860, 860, 860, 860, 860, + 860, 860, 860, 31, 39, 405, 898, 526, 530, 933, + 183, 165, 876, 374, 528, 890, 939, 174, 790, 910, + 790, 528, 561, 559, 558, 1012, 558, 1020, 860, 532, + 529, 229, 41, 467, 1019, 558, 570, 467, 528, 559, + 575, 585, 586, 588, 42, 127, 747, 532, 467, 747, + 271, 719, 374, 375, 519, 520, 766, 768, 862, 398, + 229, 296, 319, 319, 532, 523, 4, 767, 960, 767, + 374, 375, 768, 558, 953, 284, 402, 787, 528, 955, + 956, 532, 183, 467, 201, 183, 222, 782, 750, 529, + 559, 561, 559, 561, 359, 559, 359, 554, 528, 194, + 550, 957, 229, 280, 229, 467, 528, 642, 651, 652, + 823, 824, 530, 547, 548, 957, 559, 194, 957, 194, + 549, 27, 138, 395, 546, 553, 565, 633, 649, 957, + 60, 60, 561, 565, 641, 664, 60, 60, 957, 551, + 957, 359, 395, 554, 609, 611, 964, 957, 611, 964, + 957, 611, 359, 395, 554, 957, 957, 549, 957, 359, + 395, 554, 957, 957, 561, 1024, 1027, 520, 860, 930, + 743, 743, 743, 287, 287, 529, 476, 911, 742, 860, + 860, 285, 561, 986, 285, 986, 559, 340, 709, 529, + 532, 293, 174, 440, 705, 973, 597, 480, 558, 558, + 1042, 558, 558, 558, 558, 300, 672, 154, 3, 528, + 528, 154, 154, 240, 559, 639, 653, 656, 659, 669, + 671, 644, 153, 716, 154, 145, 590, 824, 154, 490, + 980, 154, 3, 43, 47, 50, 56, 82, 84, 90, + 102, 173, 175, 178, 179, 196, 211, 224, 225, 227, + 238, 240, 250, 274, 283, 305, 307, 328, 370, 400, + 420, 429, 450, 461, 478, 529, 700, 701, 967, 1043, + 532, 532, 41, 280, 295, 559, 3, 678, 564, 678, + 295, 678, 605, 860, 710, 860, 1025, 529, 532, 41, + 708, 561, 708, 280, 285, 345, 708, 60, 708, 824, + 529, 860, 860, 860, 919, 824, 861, 861, 861, 861, + 861, 861, 133, 280, 290, 861, 861, 861, 861, 861, + 861, 861, 861, 861, 861, 529, 532, 41, 815, 860, + 860, 920, 919, 824, 529, 529, 529, 908, 824, 955, + 529, 319, 375, 523, 528, 528, 735, 432, 434, 432, + 434, 558, 737, 737, 737, 860, 183, 770, 439, 479, + 761, 762, 810, 810, 794, 860, 528, 794, 169, 810, + 528, 560, 801, 810, 824, 529, 532, 818, 529, 1004, + 3, 912, 40, 40, 826, 559, 821, 821, 526, 3, + 526, 526, 960, 440, 440, 440, 440, 824, 464, 529, + 527, 908, 860, 140, 925, 926, 529, 529, 529, 860, + 19, 532, 537, 530, 529, 529, 511, 511, 529, 529, + 529, 860, 941, 942, 943, 530, 528, 860, 945, 359, + 952, 954, 860, 860, 891, 944, 529, 529, 529, 511, + 861, 861, 147, 908, 174, 133, 162, 285, 290, 447, + 458, 528, 147, 904, 860, 424, 935, 860, 922, 860, + 440, 528, 717, 860, 930, 564, 528, 528, 157, 877, + 791, 792, 817, 743, 817, 960, 859, 966, 966, 528, + 254, 280, 734, 792, 487, 1018, 41, 60, 571, 794, + 581, 588, 931, 532, 790, 517, 513, 748, 746, 297, + 899, 902, 748, 4, 960, 768, 296, 464, 765, 532, + 247, 955, 725, 60, 938, 528, 560, 60, 271, 1010, + 1010, 440, 440, 860, 280, 668, 528, 154, 528, 642, + 205, 665, 666, 623, 41, 178, 632, 662, 564, 548, + 623, 27, 138, 363, 365, 395, 543, 544, 545, 555, + 556, 154, 678, 154, 678, 633, 649, 633, 529, 532, + 561, 626, 517, 517, 530, 529, 532, 528, 528, 440, + 379, 94, 440, 567, 379, 440, 440, 440, 379, 1024, + 1028, 529, 19, 19, 527, 742, 742, 742, 911, 529, + 528, 704, 3, 414, 415, 528, 561, 715, 865, 660, + 709, 599, 558, 595, 528, 41, 41, 661, 695, 697, + 973, 361, 427, 597, 565, 601, 602, 665, 558, 558, + 1042, 558, 651, 652, 529, 532, 316, 406, 490, 492, + 645, 646, 957, 490, 1041, 558, 528, 717, 558, 637, + 41, 558, 529, 532, 823, 824, 693, 699, 696, 699, + 427, 860, 154, 558, 617, 964, 1026, 561, 561, 285, + 665, 521, 665, 561, 521, 665, 561, 529, 529, 920, + 174, 133, 290, 528, 816, 813, 528, 529, 529, 529, + 559, 754, 817, 737, 737, 737, 737, 558, 558, 558, + 60, 188, 779, 14, 529, 810, 955, 528, 798, 799, + 800, 863, 866, 955, 169, 81, 820, 819, 529, 529, + 526, 526, 824, 529, 532, 529, 960, 527, 960, 960, + 529, 847, 849, 850, 851, 850, 851, 851, 529, 436, + 860, 144, 860, 894, 904, 845, 845, 529, 532, 529, + 560, 860, 945, 946, 947, 41, 528, 941, 949, 201, + 529, 948, 859, 860, 37, 37, 860, 529, 860, 174, + 528, 912, 860, 529, 147, 861, 861, 147, 147, 860, + 860, 527, 19, 528, 932, 744, 487, 860, 306, 881, + 532, 770, 742, 770, 529, 559, 732, 733, 928, 254, + 528, 860, 367, 579, 559, 271, 327, 118, 309, 528, + 569, 716, 810, 529, 532, 575, 1018, 860, 166, 234, + 528, 748, 296, 558, 529, 956, 183, 717, 718, 938, + 956, 957, 559, 957, 529, 154, 666, 550, 666, 623, + 655, 532, 529, 120, 209, 278, 280, 650, 528, 34, + 60, 673, 662, 75, 81, 94, 118, 120, 209, 280, + 285, 335, 353, 457, 467, 628, 629, 643, 178, 118, + 193, 280, 637, 610, 108, 118, 178, 280, 413, 416, + 612, 637, 395, 545, 451, 957, 549, 553, 860, 860, + 565, 664, 908, 745, 957, 957, 957, 957, 549, 957, + 957, 957, 957, 957, 1028, 930, 930, 529, 529, 529, + 743, 108, 379, 530, 860, 610, 715, 528, 528, 659, + 716, 590, 980, 672, 194, 558, 599, 600, 860, 529, + 532, 529, 595, 528, 41, 648, 644, 559, 656, 60, + 60, 293, 637, 293, 295, 636, 607, 108, 278, 41, + 561, 591, 592, 661, 716, 695, 697, 529, 701, 13, + 14, 41, 41, 717, 718, 655, 467, 977, 678, 665, + 861, 174, 528, 912, 818, 529, 532, 529, 770, 558, + 558, 558, 558, 31, 104, 184, 373, 528, 771, 772, + 773, 774, 775, 776, 777, 860, 860, 489, 878, 860, + 529, 862, 905, 906, 201, 183, 795, 799, 529, 801, + 802, 803, 964, 826, 960, 960, 826, 559, 826, 527, + 527, 527, 860, 941, 532, 529, 559, 949, 950, 951, + 41, 860, 862, 952, 860, 860, 860, 912, 529, 860, + 37, 37, 860, 860, 147, 529, 520, 930, 529, 910, + 529, 860, 529, 528, 559, 882, 779, 529, 779, 561, + 529, 532, 971, 937, 473, 426, 466, 580, 559, 574, + 584, 295, 577, 486, 686, 688, 689, 690, 517, 588, + 579, 904, 60, 529, 529, 472, 473, 722, 623, 550, + 529, 529, 490, 658, 121, 197, 207, 120, 469, 860, + 118, 41, 528, 964, 957, 861, 121, 197, 120, 285, + 229, 558, 658, 89, 673, 194, 285, 611, 860, 673, + 285, 519, 520, 614, 559, 823, 678, 678, 517, 529, + 529, 440, 440, 527, 527, 742, 529, 529, 559, 529, + 710, 467, 706, 707, 602, 665, 529, 1041, 41, 427, + 280, 528, 528, 601, 980, 659, 153, 716, 151, 203, + 646, 528, 528, 87, 1041, 108, 590, 529, 532, 980, + 490, 1039, 860, 860, 427, 295, 559, 976, 528, 861, + 912, 529, 529, 9, 360, 760, 779, 528, 397, 528, + 529, 532, 559, 879, 880, 342, 780, 532, 529, 528, + 560, 60, 529, 201, 529, 802, 527, 527, 824, 945, + 532, 529, 559, 527, 194, 529, 860, 860, 860, 19, + 19, 527, 529, 529, 559, 883, 878, 561, 878, 928, + 529, 532, 472, 931, 529, 532, 92, 579, 253, 280, + 690, 579, 860, 529, 956, 956, 353, 658, 528, 647, + 623, 529, 193, 528, 860, 280, 629, 658, 661, 957, + 41, 154, 820, 3, 38, 43, 47, 50, 56, 60, + 82, 84, 90, 102, 173, 175, 179, 196, 211, 224, + 225, 227, 238, 240, 250, 274, 279, 283, 297, 305, + 307, 328, 370, 389, 396, 400, 420, 429, 450, 456, + 461, 478, 519, 520, 561, 611, 624, 667, 824, 902, + 961, 1043, 1049, 957, 957, 529, 610, 125, 529, 529, + 644, 716, 558, 154, 602, 41, 529, 957, 1041, 31, + 86, 95, 119, 193, 206, 413, 416, 640, 640, 636, + 908, 908, 123, 138, 334, 561, 41, 65, 75, 244, + 717, 558, 528, 559, 578, 587, 872, 529, 529, 528, + 878, 908, 528, 908, 773, 41, 532, 860, 467, 755, + 862, 938, 955, 806, 528, 806, 949, 860, 930, 930, + 315, 884, 780, 780, 716, 309, 716, 574, 295, 528, + 572, 37, 681, 253, 558, 623, 565, 654, 657, 417, + 482, 630, 631, 528, 625, 860, 529, 252, 670, 193, + 467, 552, 961, 965, 710, 561, 980, 646, 1039, 528, + 558, 529, 716, 644, 607, 529, 529, 375, 375, 716, + 75, 298, 75, 977, 860, 81, 582, 529, 532, 582, + 9, 780, 529, 772, 529, 882, 880, 377, 529, 938, + 527, 527, 527, 60, 743, 755, 755, 580, 94, 587, + 134, 860, 436, 60, 687, 661, 517, 529, 532, 609, + 529, 278, 638, 175, 314, 401, 295, 634, 635, 663, + 625, 860, 965, 523, 41, 636, 528, 1039, 646, 1041, + 1039, 298, 298, 528, 529, 964, 583, 964, 980, 578, + 583, 529, 755, 529, 757, 529, 907, 186, 346, 375, + 885, 472, 957, 529, 281, 464, 123, 134, 146, 215, + 464, 684, 407, 431, 681, 670, 624, 657, 529, 631, + 207, 123, 464, 295, 663, 295, 634, 523, 451, 716, + 636, 587, 582, 747, 817, 747, 54, 105, 453, 860, + 886, 887, 886, 886, 529, 716, 817, 395, 281, 685, + 860, 118, 528, 571, 682, 395, 571, 436, 635, 64, + 278, 366, 395, 627, 627, 451, 1039, 529, 583, 748, + 748, 887, 374, 168, 330, 168, 330, 150, 888, 888, + 888, 586, 473, 584, 521, 683, 473, 521, 586, 684, + 623, 26, 118, 285, 980, 747, 37, 105, 183, 278, + 437, 817, 529, 528, 817, 748, 887, 374, 303, 908, + 529 }; #define yyerrok (yyerrstatus = 0) @@ -21271,14 +21431,14 @@ YYLTYPE yylloc; switch (yyn) { case 2: -#line 523 "third_party/libpg_query/grammar/grammar.y" +#line 525 "third_party/libpg_query/grammar/grammar.y" { pg_yyget_extra(yyscanner)->parsetree = (yyvsp[(1) - (1)].list); ;} break; case 3: -#line 539 "third_party/libpg_query/grammar/grammar.y" +#line 541 "third_party/libpg_query/grammar/grammar.y" { if ((yyvsp[(1) - (3)].list) != NIL) { @@ -21293,7 +21453,7 @@ YYLTYPE yylloc; break; case 4: -#line 551 "third_party/libpg_query/grammar/grammar.y" +#line 553 "third_party/libpg_query/grammar/grammar.y" { if ((yyvsp[(1) - (1)].node) != NULL) (yyval.list) = list_make1(makeRawStmt((yyvsp[(1) - (1)].node), 0)); @@ -21303,7 +21463,7 @@ YYLTYPE yylloc; break; case 48: -#line 603 "third_party/libpg_query/grammar/grammar.y" +#line 605 "third_party/libpg_query/grammar/grammar.y" { (yyval.node) = NULL; ;} break; @@ -21864,7 +22024,7 @@ YYLTYPE yylloc; { PGAlterTableCmd *n = makeNode(PGAlterTableCmd); n->subtype = PG_AT_SetRelOptions; - n->def = (PGNode *)(yyvsp[(2) - (2)].list); + n->options = (yyvsp[(2) - (2)].list); (yyval.node) = (PGNode *)n; ;} break; @@ -21874,7 +22034,7 @@ YYLTYPE yylloc; { PGAlterTableCmd *n = makeNode(PGAlterTableCmd); n->subtype = PG_AT_ResetRelOptions; - n->def = (PGNode *)(yyvsp[(2) - (2)].list); + n->options = (yyvsp[(2) - (2)].list); (yyval.node) = (PGNode *)n; ;} break; @@ -23395,57 +23555,87 @@ YYLTYPE yylloc; #line 9 "third_party/libpg_query/grammar/statements/create.y" { PGCreateStmt *n = makeNode(PGCreateStmt); - (yyvsp[(4) - (9)].range)->relpersistence = (yyvsp[(2) - (9)].ival); - n->relation = (yyvsp[(4) - (9)].range); - n->tableElts = (yyvsp[(6) - (9)].list); + (yyvsp[(4) - (10)].range)->relpersistence = (yyvsp[(2) - (10)].ival); + n->relation = (yyvsp[(4) - (10)].range); + n->tableElts = (yyvsp[(6) - (10)].list); n->ofTypename = NULL; n->constraints = NIL; - n->options = (yyvsp[(8) - (9)].list); - n->oncommit = (yyvsp[(9) - (9)].oncommit); + + PGListCell *lc; + foreach(lc, (yyvsp[(8) - (10)].list)) { + PGDefElem *de = (PGDefElem *) lfirst(lc); + if (strcmp(de->defname, "partitioned_by") == 0) { + n->partition_list = (PGList *)de->arg; + } else if (strcmp(de->defname, "sorted_by") == 0) { + n->sort_list = (PGList *)de->arg; + } + } + n->options = (yyvsp[(9) - (10)].list); + n->oncommit = (yyvsp[(10) - (10)].oncommit); n->onconflict = PG_ERROR_ON_CONFLICT; (yyval.node) = (PGNode *)n; ;} break; case 293: -#line 24 "third_party/libpg_query/grammar/statements/create.y" +#line 34 "third_party/libpg_query/grammar/statements/create.y" { PGCreateStmt *n = makeNode(PGCreateStmt); - (yyvsp[(7) - (12)].range)->relpersistence = (yyvsp[(2) - (12)].ival); - n->relation = (yyvsp[(7) - (12)].range); - n->tableElts = (yyvsp[(9) - (12)].list); + (yyvsp[(7) - (13)].range)->relpersistence = (yyvsp[(2) - (13)].ival); + n->relation = (yyvsp[(7) - (13)].range); + n->tableElts = (yyvsp[(9) - (13)].list); n->ofTypename = NULL; n->constraints = NIL; - n->options = (yyvsp[(11) - (12)].list); - n->oncommit = (yyvsp[(12) - (12)].oncommit); + + PGListCell *lc; + foreach(lc, (yyvsp[(11) - (13)].list)) { + PGDefElem *de = (PGDefElem *) lfirst(lc); + if (strcmp(de->defname, "partitioned_by") == 0) { + n->partition_list = (PGList *)de->arg; + } else if (strcmp(de->defname, "sorted_by") == 0) { + n->sort_list = (PGList *)de->arg; + } + } + n->options = (yyvsp[(12) - (13)].list); + n->oncommit = (yyvsp[(13) - (13)].oncommit); n->onconflict = PG_IGNORE_ON_CONFLICT; (yyval.node) = (PGNode *)n; ;} break; case 294: -#line 39 "third_party/libpg_query/grammar/statements/create.y" +#line 59 "third_party/libpg_query/grammar/statements/create.y" { PGCreateStmt *n = makeNode(PGCreateStmt); - (yyvsp[(6) - (11)].range)->relpersistence = (yyvsp[(4) - (11)].ival); - n->relation = (yyvsp[(6) - (11)].range); - n->tableElts = (yyvsp[(8) - (11)].list); + (yyvsp[(6) - (12)].range)->relpersistence = (yyvsp[(4) - (12)].ival); + n->relation = (yyvsp[(6) - (12)].range); + n->tableElts = (yyvsp[(8) - (12)].list); n->ofTypename = NULL; n->constraints = NIL; - n->options = (yyvsp[(10) - (11)].list); - n->oncommit = (yyvsp[(11) - (11)].oncommit); + + PGListCell *lc; + foreach(lc, (yyvsp[(10) - (12)].list)) { + PGDefElem *de = (PGDefElem *) lfirst(lc); + if (strcmp(de->defname, "partitioned_by") == 0) { + n->partition_list = (PGList *)de->arg; + } else if (strcmp(de->defname, "sorted_by") == 0) { + n->sort_list = (PGList *)de->arg; + } + } + n->options = (yyvsp[(11) - (12)].list); + n->oncommit = (yyvsp[(12) - (12)].oncommit); n->onconflict = PG_REPLACE_ON_CONFLICT; (yyval.node) = (PGNode *)n; ;} break; case 295: -#line 56 "third_party/libpg_query/grammar/statements/create.y" +#line 86 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = 0; ;} break; case 296: -#line 58 "third_party/libpg_query/grammar/statements/create.y" +#line 88 "third_party/libpg_query/grammar/statements/create.y" { /* * We must complain about conflicting options. @@ -23472,77 +23662,77 @@ YYLTYPE yylloc; break; case 297: -#line 84 "third_party/libpg_query/grammar/statements/create.y" +#line 114 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (PGNode *)(yyvsp[(1) - (1)].typnam); ;} break; case 298: -#line 85 "third_party/libpg_query/grammar/statements/create.y" +#line 115 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (PGNode *)makeString(pstrdup((yyvsp[(1) - (1)].keyword))); ;} break; case 299: -#line 86 "third_party/libpg_query/grammar/statements/create.y" +#line 116 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (PGNode *)(yyvsp[(1) - (1)].list); ;} break; case 300: -#line 87 "third_party/libpg_query/grammar/statements/create.y" +#line 117 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (PGNode *)(yyvsp[(1) - (1)].value); ;} break; case 301: -#line 88 "third_party/libpg_query/grammar/statements/create.y" +#line 118 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (PGNode *)makeString((yyvsp[(1) - (1)].str)); ;} break; case 302: -#line 89 "third_party/libpg_query/grammar/statements/create.y" +#line 119 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (PGNode *)makeString(pstrdup((yyvsp[(1) - (1)].keyword))); ;} break; case 303: -#line 93 "third_party/libpg_query/grammar/statements/create.y" +#line 123 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; case 304: -#line 94 "third_party/libpg_query/grammar/statements/create.y" +#line 124 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = NIL; ;} break; case 305: -#line 99 "third_party/libpg_query/grammar/statements/create.y" +#line 128 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (PGNode *) makeString((yyvsp[(1) - (1)].str)); ;} break; case 306: -#line 104 "third_party/libpg_query/grammar/statements/create.y" +#line 133 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_FKCONSTR_ACTION_NOACTION; ;} break; case 307: -#line 105 "third_party/libpg_query/grammar/statements/create.y" +#line 134 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_FKCONSTR_ACTION_RESTRICT; ;} break; case 308: -#line 106 "third_party/libpg_query/grammar/statements/create.y" +#line 135 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_FKCONSTR_ACTION_CASCADE; ;} break; case 309: -#line 107 "third_party/libpg_query/grammar/statements/create.y" +#line 136 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_FKCONSTR_ACTION_SETNULL; ;} break; case 310: -#line 108 "third_party/libpg_query/grammar/statements/create.y" +#line 137 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_FKCONSTR_ACTION_SETDEFAULT; ;} break; case 311: -#line 114 "third_party/libpg_query/grammar/statements/create.y" +#line 143 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = castNode(PGConstraint, (yyvsp[(3) - (3)].node)); n->conname = (yyvsp[(2) - (3)].str); @@ -23552,17 +23742,17 @@ YYLTYPE yylloc; break; case 312: -#line 120 "third_party/libpg_query/grammar/statements/create.y" +#line 149 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 313: -#line 121 "third_party/libpg_query/grammar/statements/create.y" +#line 150 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 314: -#line 123 "third_party/libpg_query/grammar/statements/create.y" +#line 152 "third_party/libpg_query/grammar/statements/create.y" { /* * Note: the PGCollateClause is momentarily included in @@ -23578,7 +23768,7 @@ YYLTYPE yylloc; break; case 315: -#line 140 "third_party/libpg_query/grammar/statements/create.y" +#line 169 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_NOTNULL; @@ -23588,7 +23778,7 @@ YYLTYPE yylloc; break; case 316: -#line 147 "third_party/libpg_query/grammar/statements/create.y" +#line 176 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_NULL; @@ -23598,7 +23788,7 @@ YYLTYPE yylloc; break; case 317: -#line 154 "third_party/libpg_query/grammar/statements/create.y" +#line 183 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_UNIQUE; @@ -23611,7 +23801,7 @@ YYLTYPE yylloc; break; case 318: -#line 164 "third_party/libpg_query/grammar/statements/create.y" +#line 193 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_PRIMARY; @@ -23624,7 +23814,7 @@ YYLTYPE yylloc; break; case 319: -#line 174 "third_party/libpg_query/grammar/statements/create.y" +#line 203 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_CHECK; @@ -23639,7 +23829,7 @@ YYLTYPE yylloc; break; case 320: -#line 186 "third_party/libpg_query/grammar/statements/create.y" +#line 215 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_COMPRESSION; @@ -23650,7 +23840,7 @@ YYLTYPE yylloc; break; case 321: -#line 194 "third_party/libpg_query/grammar/statements/create.y" +#line 223 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_DEFAULT; @@ -23662,7 +23852,7 @@ YYLTYPE yylloc; break; case 322: -#line 203 "third_party/libpg_query/grammar/statements/create.y" +#line 232 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_FOREIGN; @@ -23680,27 +23870,27 @@ YYLTYPE yylloc; break; case 323: -#line 220 "third_party/libpg_query/grammar/statements/create.y" +#line 249 "third_party/libpg_query/grammar/statements/create.y" { (yyval.constr) = PG_CONSTR_GENERATED_VIRTUAL; ;} break; case 324: -#line 221 "third_party/libpg_query/grammar/statements/create.y" +#line 250 "third_party/libpg_query/grammar/statements/create.y" { (yyval.constr) = PG_CONSTR_GENERATED_STORED; ;} break; case 325: -#line 225 "third_party/libpg_query/grammar/statements/create.y" +#line 254 "third_party/libpg_query/grammar/statements/create.y" { (yyval.constr) = (yyvsp[(1) - (1)].constr); ;} break; case 326: -#line 226 "third_party/libpg_query/grammar/statements/create.y" +#line 255 "third_party/libpg_query/grammar/statements/create.y" { (yyval.constr) = PG_CONSTR_GENERATED_VIRTUAL; ;} break; case 327: -#line 231 "third_party/libpg_query/grammar/statements/create.y" +#line 260 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_IDENTITY; @@ -23712,7 +23902,7 @@ YYLTYPE yylloc; break; case 328: -#line 240 "third_party/libpg_query/grammar/statements/create.y" +#line 269 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = (yyvsp[(7) - (7)].constr); @@ -23738,7 +23928,7 @@ YYLTYPE yylloc; break; case 329: -#line 263 "third_party/libpg_query/grammar/statements/create.y" +#line 292 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = (yyvsp[(5) - (5)].constr); @@ -23751,79 +23941,79 @@ YYLTYPE yylloc; break; case 330: -#line 277 "third_party/libpg_query/grammar/statements/create.y" +#line 306 "third_party/libpg_query/grammar/statements/create.y" { (yyval.defelt) = makeDefElem((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 331: -#line 283 "third_party/libpg_query/grammar/statements/create.y" +#line 312 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = (yyvsp[(3) - (3)].ival); ;} break; case 332: -#line 289 "third_party/libpg_query/grammar/statements/create.y" +#line 318 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = ((yyvsp[(1) - (1)].ival) << 8) | (PG_FKCONSTR_ACTION_NOACTION & 0xFF); ;} break; case 333: -#line 291 "third_party/libpg_query/grammar/statements/create.y" +#line 320 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = (PG_FKCONSTR_ACTION_NOACTION << 8) | ((yyvsp[(1) - (1)].ival) & 0xFF); ;} break; case 334: -#line 293 "third_party/libpg_query/grammar/statements/create.y" +#line 322 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = ((yyvsp[(1) - (2)].ival) << 8) | ((yyvsp[(2) - (2)].ival) & 0xFF); ;} break; case 335: -#line 295 "third_party/libpg_query/grammar/statements/create.y" +#line 324 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = ((yyvsp[(2) - (2)].ival) << 8) | ((yyvsp[(1) - (2)].ival) & 0xFF); ;} break; case 336: -#line 297 "third_party/libpg_query/grammar/statements/create.y" +#line 326 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = (PG_FKCONSTR_ACTION_NOACTION << 8) | (PG_FKCONSTR_ACTION_NOACTION & 0xFF); ;} break; case 337: -#line 300 "third_party/libpg_query/grammar/statements/create.y" +#line 329 "third_party/libpg_query/grammar/statements/create.y" { (yyval.oncommit) = ONCOMMIT_DROP; ;} break; case 338: -#line 301 "third_party/libpg_query/grammar/statements/create.y" +#line 330 "third_party/libpg_query/grammar/statements/create.y" { (yyval.oncommit) = PG_ONCOMMIT_DELETE_ROWS; ;} break; case 339: -#line 302 "third_party/libpg_query/grammar/statements/create.y" +#line 331 "third_party/libpg_query/grammar/statements/create.y" { (yyval.oncommit) = PG_ONCOMMIT_PRESERVE_ROWS; ;} break; case 340: -#line 303 "third_party/libpg_query/grammar/statements/create.y" +#line 332 "third_party/libpg_query/grammar/statements/create.y" { (yyval.oncommit) = PG_ONCOMMIT_NOOP; ;} break; case 341: -#line 308 "third_party/libpg_query/grammar/statements/create.y" +#line 337 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; case 342: -#line 312 "third_party/libpg_query/grammar/statements/create.y" +#line 340 "third_party/libpg_query/grammar/statements/create.y" { (yyval.boolean) = true; ;} break; case 343: -#line 313 "third_party/libpg_query/grammar/statements/create.y" +#line 341 "third_party/libpg_query/grammar/statements/create.y" { (yyval.boolean) = false; ;} break; case 344: -#line 319 "third_party/libpg_query/grammar/statements/create.y" +#line 347 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = castNode(PGConstraint, (yyvsp[(3) - (3)].node)); n->conname = (yyvsp[(2) - (3)].str); @@ -23833,67 +24023,67 @@ YYLTYPE yylloc; break; case 345: -#line 325 "third_party/libpg_query/grammar/statements/create.y" +#line 353 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 346: -#line 330 "third_party/libpg_query/grammar/statements/create.y" +#line 358 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_CREATE_TABLE_LIKE_COMMENTS; ;} break; case 347: -#line 331 "third_party/libpg_query/grammar/statements/create.y" +#line 359 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_CREATE_TABLE_LIKE_CONSTRAINTS; ;} break; case 348: -#line 332 "third_party/libpg_query/grammar/statements/create.y" +#line 360 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_CREATE_TABLE_LIKE_DEFAULTS; ;} break; case 349: -#line 333 "third_party/libpg_query/grammar/statements/create.y" +#line 361 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_CREATE_TABLE_LIKE_IDENTITY; ;} break; case 350: -#line 334 "third_party/libpg_query/grammar/statements/create.y" +#line 362 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_CREATE_TABLE_LIKE_INDEXES; ;} break; case 351: -#line 335 "third_party/libpg_query/grammar/statements/create.y" +#line 363 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_CREATE_TABLE_LIKE_STATISTICS; ;} break; case 352: -#line 336 "third_party/libpg_query/grammar/statements/create.y" +#line 364 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_CREATE_TABLE_LIKE_STORAGE; ;} break; case 353: -#line 337 "third_party/libpg_query/grammar/statements/create.y" +#line 365 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_CREATE_TABLE_LIKE_ALL; ;} break; case 354: -#line 343 "third_party/libpg_query/grammar/statements/create.y" +#line 371 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].defelt)); ;} break; case 355: -#line 344 "third_party/libpg_query/grammar/statements/create.y" +#line 372 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].defelt)); ;} break; case 356: -#line 348 "third_party/libpg_query/grammar/statements/create.y" +#line 375 "third_party/libpg_query/grammar/statements/create.y" { (yyval.str) = (yyvsp[(3) - (3)].str); ;} break; case 357: -#line 354 "third_party/libpg_query/grammar/statements/create.y" +#line 381 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_ATTR_DEFERRABLE; @@ -23903,7 +24093,7 @@ YYLTYPE yylloc; break; case 358: -#line 361 "third_party/libpg_query/grammar/statements/create.y" +#line 388 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_ATTR_NOT_DEFERRABLE; @@ -23913,7 +24103,7 @@ YYLTYPE yylloc; break; case 359: -#line 368 "third_party/libpg_query/grammar/statements/create.y" +#line 395 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_ATTR_DEFERRED; @@ -23923,7 +24113,7 @@ YYLTYPE yylloc; break; case 360: -#line 375 "third_party/libpg_query/grammar/statements/create.y" +#line 402 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_ATTR_IMMEDIATE; @@ -23933,82 +24123,106 @@ YYLTYPE yylloc; break; case 361: -#line 386 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.list) = (yyvsp[(2) - (2)].list); ;} +#line 412 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].defelt)); ;} break; case 362: -#line 387 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.list) = list_make1(makeDefElem("oids", (PGNode *) makeInteger(true), (yylsp[(1) - (2)]))); ;} +#line 413 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.list) = NIL; ;} break; case 363: -#line 388 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.list) = list_make1(makeDefElem("oids", (PGNode *) makeInteger(false), (yylsp[(1) - (2)]))); ;} +#line 418 "third_party/libpg_query/grammar/statements/create.y" + { + (yyval.defelt) = makeDefElem("partitioned_by", (PGNode *)(yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); + ;} break; case 364: -#line 389 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.list) = NIL; ;} +#line 422 "third_party/libpg_query/grammar/statements/create.y" + { + (yyval.defelt) = makeDefElem("sorted_by", (PGNode *)(yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); + ;} break; case 365: -#line 393 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.list) = (yyvsp[(2) - (3)].list); ;} +#line 428 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; case 366: -#line 398 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.ival) = (yyvsp[(1) - (3)].ival) | (yyvsp[(3) - (3)].ival); ;} +#line 429 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.list) = list_make1(makeDefElem("oids", (PGNode *) makeInteger(true), (yylsp[(1) - (2)]))); ;} break; case 367: -#line 399 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.ival) = (yyvsp[(1) - (3)].ival) & ~(yyvsp[(3) - (3)].ival); ;} +#line 430 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.list) = list_make1(makeDefElem("oids", (PGNode *) makeInteger(false), (yylsp[(1) - (2)]))); ;} break; case 368: -#line 400 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.ival) = 0; ;} +#line 431 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.list) = NIL; ;} break; case 369: -#line 405 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.str) = (yyvsp[(1) - (1)].str); ;} +#line 434 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; case 370: -#line 410 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.ival) = CAS_NOT_DEFERRABLE; ;} +#line 439 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.ival) = (yyvsp[(1) - (3)].ival) | (yyvsp[(3) - (3)].ival); ;} break; case 371: -#line 411 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.ival) = CAS_DEFERRABLE; ;} +#line 440 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.ival) = (yyvsp[(1) - (3)].ival) & ~(yyvsp[(3) - (3)].ival); ;} break; case 372: -#line 412 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.ival) = CAS_INITIALLY_IMMEDIATE; ;} +#line 441 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.ival) = 0; ;} break; case 373: -#line 413 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.ival) = CAS_INITIALLY_DEFERRED; ;} +#line 446 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 374: -#line 414 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.ival) = CAS_NOT_VALID; ;} +#line 451 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.ival) = CAS_NOT_DEFERRABLE; ;} break; case 375: -#line 415 "third_party/libpg_query/grammar/statements/create.y" - { (yyval.ival) = CAS_NO_INHERIT; ;} +#line 452 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.ival) = CAS_DEFERRABLE; ;} break; case 376: -#line 421 "third_party/libpg_query/grammar/statements/create.y" +#line 453 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.ival) = CAS_INITIALLY_IMMEDIATE; ;} + break; + + case 377: +#line 454 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.ival) = CAS_INITIALLY_DEFERRED; ;} + break; + + case 378: +#line 455 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.ival) = CAS_NOT_VALID; ;} + break; + + case 379: +#line 456 "third_party/libpg_query/grammar/statements/create.y" + { (yyval.ival) = CAS_NO_INHERIT; ;} + break; + + case 380: +#line 462 "third_party/libpg_query/grammar/statements/create.y" { PGColumnDef *n = makeNode(PGColumnDef); n->category = COL_STANDARD; @@ -24027,8 +24241,8 @@ YYLTYPE yylloc; ;} break; - case 377: -#line 441 "third_party/libpg_query/grammar/statements/create.y" + case 381: +#line 482 "third_party/libpg_query/grammar/statements/create.y" { PGColumnDef *n = makeNode(PGColumnDef); n->category = COL_GENERATED; @@ -24054,8 +24268,8 @@ YYLTYPE yylloc; ;} break; - case 378: -#line 467 "third_party/libpg_query/grammar/statements/create.y" + case 382: +#line 508 "third_party/libpg_query/grammar/statements/create.y" { PGColumnDef *n = (PGColumnDef *) (yyvsp[(2) - (2)].node); n->colname = (yyvsp[(1) - (2)].str); @@ -24064,8 +24278,8 @@ YYLTYPE yylloc; ;} break; - case 379: -#line 475 "third_party/libpg_query/grammar/statements/create.y" + case 383: +#line 516 "third_party/libpg_query/grammar/statements/create.y" { PGColumnDef *n = (PGColumnDef *) (yyvsp[(2) - (2)].node); n->colname = (yyvsp[(1) - (2)].str); @@ -24074,163 +24288,177 @@ YYLTYPE yylloc; ;} break; - case 380: -#line 484 "third_party/libpg_query/grammar/statements/create.y" + case 384: +#line 525 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].defelt)); ;} break; - case 381: -#line 485 "third_party/libpg_query/grammar/statements/create.y" + case 385: +#line 526 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].defelt)); ;} break; - case 382: -#line 489 "third_party/libpg_query/grammar/statements/create.y" + case 386: +#line 530 "third_party/libpg_query/grammar/statements/create.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 383: -#line 493 "third_party/libpg_query/grammar/statements/create.y" + case 387: +#line 534 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 384: -#line 494 "third_party/libpg_query/grammar/statements/create.y" + case 388: +#line 535 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 385: -#line 495 "third_party/libpg_query/grammar/statements/create.y" + case 389: +#line 536 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 386: -#line 500 "third_party/libpg_query/grammar/statements/create.y" + case 390: +#line 541 "third_party/libpg_query/grammar/statements/create.y" { (yyval.defelt) = makeDefElem((yyvsp[(1) - (3)].str), (PGNode *) (yyvsp[(3) - (3)].node), (yylsp[(1) - (3)])); ;} break; - case 387: -#line 504 "third_party/libpg_query/grammar/statements/create.y" + case 391: +#line 545 "third_party/libpg_query/grammar/statements/create.y" { (yyval.defelt) = makeDefElem((yyvsp[(1) - (1)].str), NULL, (yylsp[(1) - (1)])); ;} break; - case 388: -#line 511 "third_party/libpg_query/grammar/statements/create.y" + case 392: +#line 552 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 389: -#line 512 "third_party/libpg_query/grammar/statements/create.y" + case 393: +#line 553 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = NIL; ;} break; - case 390: -#line 517 "third_party/libpg_query/grammar/statements/create.y" + case 394: +#line 558 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 391: -#line 518 "third_party/libpg_query/grammar/statements/create.y" + case 395: +#line 559 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 392: -#line 519 "third_party/libpg_query/grammar/statements/create.y" + case 396: +#line 560 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = NIL; ;} break; - case 393: -#line 524 "third_party/libpg_query/grammar/statements/create.y" + case 397: +#line 565 "third_party/libpg_query/grammar/statements/create.y" { (yyval.node) = (PGNode *) makeString((yyvsp[(1) - (1)].str)); ;} break; - case 394: -#line 531 "third_party/libpg_query/grammar/statements/create.y" + case 398: +#line 572 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 395: -#line 532 "third_party/libpg_query/grammar/statements/create.y" + case 399: +#line 573 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = NIL; ;} break; - case 396: -#line 537 "third_party/libpg_query/grammar/statements/create.y" + case 400: +#line 578 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 397: -#line 538 "third_party/libpg_query/grammar/statements/create.y" + case 401: +#line 579 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = NIL; ;} break; - case 398: -#line 542 "third_party/libpg_query/grammar/statements/create.y" + case 402: +#line 583 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = (yyvsp[(3) - (3)].ival); ;} break; - case 399: -#line 548 "third_party/libpg_query/grammar/statements/create.y" + case 403: +#line 589 "third_party/libpg_query/grammar/statements/create.y" { (yyval.defelt) = makeDefElem((yyvsp[(1) - (3)].str), (PGNode *) (yyvsp[(3) - (3)].node), (yylsp[(1) - (3)])); ;} break; - case 400: -#line 552 "third_party/libpg_query/grammar/statements/create.y" + case 404: +#line 593 "third_party/libpg_query/grammar/statements/create.y" { (yyval.defelt) = makeDefElem((yyvsp[(1) - (1)].str), NULL, (yylsp[(1) - (1)])); ;} break; - case 401: -#line 556 "third_party/libpg_query/grammar/statements/create.y" + case 405: +#line 597 "third_party/libpg_query/grammar/statements/create.y" { (yyval.defelt) = makeDefElemExtended((yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (PGNode *) (yyvsp[(5) - (5)].node), PG_DEFELEM_UNSPEC, (yylsp[(1) - (5)])); ;} break; - case 402: -#line 561 "third_party/libpg_query/grammar/statements/create.y" + case 406: +#line 602 "third_party/libpg_query/grammar/statements/create.y" { (yyval.defelt) = makeDefElemExtended((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str), NULL, PG_DEFELEM_UNSPEC, (yylsp[(1) - (3)])); ;} break; - case 403: -#line 568 "third_party/libpg_query/grammar/statements/create.y" + case 407: +#line 606 "third_party/libpg_query/grammar/statements/create.y" + { + (yyval.defelt) = makeDefElem((yyvsp[(1) - (3)].str), (PGNode *) (yyvsp[(3) - (3)].node), (yylsp[(1) - (3)])); + ;} + break; + + case 408: +#line 610 "third_party/libpg_query/grammar/statements/create.y" + { + (yyval.defelt) = makeDefElem((yyvsp[(1) - (1)].str), NULL, (yylsp[(1) - (1)])); + ;} + break; + + case 409: +#line 616 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 404: -#line 569 "third_party/libpg_query/grammar/statements/create.y" + case 410: +#line 617 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 405: -#line 573 "third_party/libpg_query/grammar/statements/create.y" + case 411: +#line 621 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 406: -#line 574 "third_party/libpg_query/grammar/statements/create.y" + case 412: +#line 622 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 407: -#line 578 "third_party/libpg_query/grammar/statements/create.y" + case 413: +#line 626 "third_party/libpg_query/grammar/statements/create.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 408: -#line 580 "third_party/libpg_query/grammar/statements/create.y" + case 414: +#line 628 "third_party/libpg_query/grammar/statements/create.y" { (yyval.typnam) = makeTypeNameFromNameList(lcons(makeString((yyvsp[(1) - (4)].str)), (yyvsp[(2) - (4)].list))); (yyval.typnam)->pct_type = true; @@ -24238,8 +24466,8 @@ YYLTYPE yylloc; ;} break; - case 409: -#line 586 "third_party/libpg_query/grammar/statements/create.y" + case 415: +#line 634 "third_party/libpg_query/grammar/statements/create.y" { (yyval.typnam) = makeTypeNameFromNameList(lcons(makeString((yyvsp[(2) - (5)].str)), (yyvsp[(3) - (5)].list))); (yyval.typnam)->pct_type = true; @@ -24248,8 +24476,8 @@ YYLTYPE yylloc; ;} break; - case 410: -#line 597 "third_party/libpg_query/grammar/statements/create.y" + case 416: +#line 645 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_CHECK; @@ -24264,8 +24492,8 @@ YYLTYPE yylloc; ;} break; - case 411: -#line 611 "third_party/libpg_query/grammar/statements/create.y" + case 417: +#line 659 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_UNIQUE; @@ -24280,8 +24508,8 @@ YYLTYPE yylloc; ;} break; - case 412: -#line 624 "third_party/libpg_query/grammar/statements/create.y" + case 418: +#line 672 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_UNIQUE; @@ -24297,8 +24525,8 @@ YYLTYPE yylloc; ;} break; - case 413: -#line 639 "third_party/libpg_query/grammar/statements/create.y" + case 419: +#line 687 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_PRIMARY; @@ -24313,8 +24541,8 @@ YYLTYPE yylloc; ;} break; - case 414: -#line 652 "third_party/libpg_query/grammar/statements/create.y" + case 420: +#line 700 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_PRIMARY; @@ -24330,8 +24558,8 @@ YYLTYPE yylloc; ;} break; - case 415: -#line 667 "third_party/libpg_query/grammar/statements/create.y" + case 421: +#line 715 "third_party/libpg_query/grammar/statements/create.y" { PGConstraint *n = makeNode(PGConstraint); n->contype = PG_CONSTR_FOREIGN; @@ -24351,29 +24579,29 @@ YYLTYPE yylloc; ;} break; - case 416: -#line 689 "third_party/libpg_query/grammar/statements/create.y" + case 422: +#line 737 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 417: -#line 693 "third_party/libpg_query/grammar/statements/create.y" + case 423: +#line 741 "third_party/libpg_query/grammar/statements/create.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 418: -#line 700 "third_party/libpg_query/grammar/statements/create.y" + case 424: +#line 748 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_FKCONSTR_MATCH_FULL; ;} break; - case 419: -#line 704 "third_party/libpg_query/grammar/statements/create.y" + case 425: +#line 752 "third_party/libpg_query/grammar/statements/create.y" { ereport(ERROR, (errcode(PG_ERRCODE_FEATURE_NOT_SUPPORTED), @@ -24383,22 +24611,22 @@ YYLTYPE yylloc; ;} break; - case 420: -#line 712 "third_party/libpg_query/grammar/statements/create.y" + case 426: +#line 760 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_FKCONSTR_MATCH_SIMPLE; ;} break; - case 421: -#line 716 "third_party/libpg_query/grammar/statements/create.y" + case 427: +#line 764 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_FKCONSTR_MATCH_SIMPLE; ;} break; - case 422: -#line 724 "third_party/libpg_query/grammar/statements/create.y" + case 428: +#line 772 "third_party/libpg_query/grammar/statements/create.y" { PGTableLikeClause *n = makeNode(PGTableLikeClause); n->relation = (yyvsp[(2) - (3)].range); @@ -24407,28 +24635,28 @@ YYLTYPE yylloc; ;} break; - case 423: -#line 733 "third_party/libpg_query/grammar/statements/create.y" + case 429: +#line 781 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_RELPERSISTENCE_TEMP; ;} break; - case 424: -#line 734 "third_party/libpg_query/grammar/statements/create.y" + case 430: +#line 782 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_RELPERSISTENCE_TEMP; ;} break; - case 425: -#line 735 "third_party/libpg_query/grammar/statements/create.y" + case 431: +#line 783 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_RELPERSISTENCE_TEMP; ;} break; - case 426: -#line 736 "third_party/libpg_query/grammar/statements/create.y" + case 432: +#line 784 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_RELPERSISTENCE_TEMP; ;} break; - case 427: -#line 738 "third_party/libpg_query/grammar/statements/create.y" + case 433: +#line 786 "third_party/libpg_query/grammar/statements/create.y" { ereport(PGWARNING, (errmsg("GLOBAL is deprecated in temporary table creation"), @@ -24437,8 +24665,8 @@ YYLTYPE yylloc; ;} break; - case 428: -#line 745 "third_party/libpg_query/grammar/statements/create.y" + case 434: +#line 793 "third_party/libpg_query/grammar/statements/create.y" { ereport(PGWARNING, (errmsg("GLOBAL is deprecated in temporary table creation"), @@ -24447,27 +24675,27 @@ YYLTYPE yylloc; ;} break; - case 429: -#line 751 "third_party/libpg_query/grammar/statements/create.y" + case 435: +#line 799 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_RELPERSISTENCE_UNLOGGED; ;} break; - case 430: -#line 752 "third_party/libpg_query/grammar/statements/create.y" + case 436: +#line 800 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = RELPERSISTENCE_PERMANENT; ;} break; - case 431: -#line 757 "third_party/libpg_query/grammar/statements/create.y" + case 437: +#line 804 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = PG_ATTRIBUTE_IDENTITY_ALWAYS; ;} break; - case 432: -#line 758 "third_party/libpg_query/grammar/statements/create.y" + case 438: +#line 805 "third_party/libpg_query/grammar/statements/create.y" { (yyval.ival) = ATTRIBUTE_IDENTITY_BY_DEFAULT; ;} break; - case 433: + case 439: #line 10 "third_party/libpg_query/grammar/statements/drop.y" { PGDropStmt *n = makeNode(PGDropStmt); @@ -24480,7 +24708,7 @@ YYLTYPE yylloc; ;} break; - case 434: + case 440: #line 20 "third_party/libpg_query/grammar/statements/drop.y" { PGDropStmt *n = makeNode(PGDropStmt); @@ -24493,7 +24721,7 @@ YYLTYPE yylloc; ;} break; - case 435: + case 441: #line 30 "third_party/libpg_query/grammar/statements/drop.y" { PGDropStmt *n = makeNode(PGDropStmt); @@ -24506,7 +24734,7 @@ YYLTYPE yylloc; ;} break; - case 436: + case 442: #line 40 "third_party/libpg_query/grammar/statements/drop.y" { PGDropStmt *n = makeNode(PGDropStmt); @@ -24519,7 +24747,7 @@ YYLTYPE yylloc; ;} break; - case 437: + case 443: #line 50 "third_party/libpg_query/grammar/statements/drop.y" { PGDropStmt *n = makeNode(PGDropStmt); @@ -24532,7 +24760,7 @@ YYLTYPE yylloc; ;} break; - case 438: + case 444: #line 60 "third_party/libpg_query/grammar/statements/drop.y" { PGDropStmt *n = makeNode(PGDropStmt); @@ -24545,167 +24773,167 @@ YYLTYPE yylloc; ;} break; - case 439: + case 445: #line 73 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_TABLE; ;} break; - case 440: + case 446: #line 74 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_SEQUENCE; ;} break; - case 441: + case 447: #line 75 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_FUNCTION; ;} break; - case 442: + case 448: #line 76 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_FUNCTION; ;} break; - case 443: + case 449: #line 77 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_TABLE_MACRO; ;} break; - case 444: + case 450: #line 78 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_VIEW; ;} break; - case 445: + case 451: #line 79 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_MATVIEW; ;} break; - case 446: + case 452: #line 80 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_INDEX; ;} break; - case 447: + case 453: #line 81 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_FOREIGN_TABLE; ;} break; - case 448: + case 454: #line 82 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_COLLATION; ;} break; - case 449: + case 455: #line 83 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_CONVERSION; ;} break; - case 450: + case 456: #line 84 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_SCHEMA; ;} break; - case 451: + case 457: #line 85 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_STATISTIC_EXT; ;} break; - case 452: + case 458: #line 86 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_TSPARSER; ;} break; - case 453: + case 459: #line 87 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_TSDICTIONARY; ;} break; - case 454: + case 460: #line 88 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_TSTEMPLATE; ;} break; - case 455: + case 461: #line 89 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_TSCONFIGURATION; ;} break; - case 456: + case 462: #line 90 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_TYPE; ;} break; - case 457: + case 463: #line 95 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_ACCESS_METHOD; ;} break; - case 458: + case 464: #line 96 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_EVENT_TRIGGER; ;} break; - case 459: + case 465: #line 97 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_EXTENSION; ;} break; - case 460: + case 466: #line 98 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_FDW; ;} break; - case 461: + case 467: #line 99 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_PUBLICATION; ;} break; - case 462: + case 468: #line 100 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_FOREIGN_SERVER; ;} break; - case 463: + case 469: #line 105 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 464: + case 470: #line 106 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 465: + case 471: #line 111 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.dbehavior) = PG_DROP_CASCADE; ;} break; - case 466: + case 472: #line 112 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.dbehavior) = PG_DROP_RESTRICT; ;} break; - case 467: + case 473: #line 113 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.dbehavior) = PG_DROP_RESTRICT; /* default */ ;} break; - case 468: + case 474: #line 118 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_POLICY; ;} break; - case 469: + case 475: #line 119 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_RULE; ;} break; - case 470: + case 476: #line 120 "third_party/libpg_query/grammar/statements/drop.y" { (yyval.objtype) = PG_OBJECT_TRIGGER; ;} break; - case 471: + case 477: #line 13 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMergeIntoStmt *n = makeNode(PGMergeIntoStmt); @@ -24722,27 +24950,27 @@ YYLTYPE yylloc; ;} break; - case 472: + case 478: #line 29 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 473: + case 479: #line 30 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.node) = NULL; ;} break; - case 474: + case 480: #line 34 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 475: + case 481: #line 35 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.list) = NULL; ;} break; - case 478: + case 484: #line 44 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = makeNode(PGMatchAction); @@ -24753,7 +24981,7 @@ YYLTYPE yylloc; ;} break; - case 479: + case 485: #line 52 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = makeNode(PGMatchAction); @@ -24763,7 +24991,7 @@ YYLTYPE yylloc; ;} break; - case 480: + case 486: #line 59 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = makeNode(PGMatchAction); @@ -24773,7 +25001,7 @@ YYLTYPE yylloc; ;} break; - case 481: + case 487: #line 66 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = makeNode(PGMatchAction); @@ -24782,7 +25010,7 @@ YYLTYPE yylloc; ;} break; - case 482: + case 488: #line 72 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = makeNode(PGMatchAction); @@ -24794,7 +25022,7 @@ YYLTYPE yylloc; ;} break; - case 483: + case 489: #line 81 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = makeNode(PGMatchAction); @@ -24804,7 +25032,7 @@ YYLTYPE yylloc; ;} break; - case 484: + case 490: #line 88 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = makeNode(PGMatchAction); @@ -24815,7 +25043,7 @@ YYLTYPE yylloc; ;} break; - case 485: + case 491: #line 96 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = makeNode(PGMatchAction); @@ -24824,7 +25052,7 @@ YYLTYPE yylloc; ;} break; - case 486: + case 492: #line 102 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = makeNode(PGMatchAction); @@ -24834,17 +25062,17 @@ YYLTYPE yylloc; ;} break; - case 487: + case 493: #line 111 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 488: + case 494: #line 112 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.node) = NULL; ;} break; - case 489: + case 495: #line 117 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = (PGMatchAction *) (yyvsp[(5) - (5)].node); @@ -24854,22 +25082,22 @@ YYLTYPE yylloc; ;} break; - case 490: + case 496: #line 126 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.mergeaction) = MERGE_ACTION_WHEN_NOT_MATCHED_BY_SOURCE; ;} break; - case 491: + case 497: #line 127 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.mergeaction) = MERGE_ACTION_WHEN_NOT_MATCHED_BY_TARGET; ;} break; - case 492: + case 498: #line 128 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.mergeaction) = MERGE_ACTION_WHEN_NOT_MATCHED_BY_TARGET; ;} break; - case 493: + case 499: #line 133 "third_party/libpg_query/grammar/statements/merge_into.y" { PGMatchAction *n = (PGMatchAction *) (yyvsp[(7) - (7)].node); @@ -24879,17 +25107,17 @@ YYLTYPE yylloc; ;} break; - case 496: + case 502: #line 146 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 497: + case 503: #line 147 "third_party/libpg_query/grammar/statements/merge_into.y" { (yyval.list) = list_concat(list_make1((yyvsp[(1) - (2)].node)), (yyvsp[(2) - (2)].list)); ;} break; - case 498: + case 504: #line 8 "third_party/libpg_query/grammar/statements/create_function.y" { PGCreateFunctionStmt *n = makeNode(PGCreateFunctionStmt); @@ -24901,7 +25129,7 @@ YYLTYPE yylloc; ;} break; - case 499: + case 505: #line 17 "third_party/libpg_query/grammar/statements/create_function.y" { PGCreateFunctionStmt *n = makeNode(PGCreateFunctionStmt); @@ -24913,7 +25141,7 @@ YYLTYPE yylloc; ;} break; - case 500: + case 506: #line 26 "third_party/libpg_query/grammar/statements/create_function.y" { PGCreateFunctionStmt *n = makeNode(PGCreateFunctionStmt); @@ -24925,7 +25153,7 @@ YYLTYPE yylloc; ;} break; - case 501: + case 507: #line 35 "third_party/libpg_query/grammar/statements/create_function.y" { PGCreateFunctionStmt *n = makeNode(PGCreateFunctionStmt); @@ -24937,7 +25165,7 @@ YYLTYPE yylloc; ;} break; - case 502: + case 508: #line 44 "third_party/libpg_query/grammar/statements/create_function.y" { PGCreateFunctionStmt *n = makeNode(PGCreateFunctionStmt); @@ -24949,7 +25177,7 @@ YYLTYPE yylloc; ;} break; - case 503: + case 509: #line 53 "third_party/libpg_query/grammar/statements/create_function.y" { PGCreateFunctionStmt *n = makeNode(PGCreateFunctionStmt); @@ -24961,7 +25189,7 @@ YYLTYPE yylloc; ;} break; - case 504: + case 510: #line 65 "third_party/libpg_query/grammar/statements/create_function.y" { PGFunctionDefinition *n = makeNode(PGFunctionDefinition); @@ -24971,7 +25199,7 @@ YYLTYPE yylloc; ;} break; - case 505: + case 511: #line 75 "third_party/libpg_query/grammar/statements/create_function.y" { PGFunctionDefinition *n = makeNode(PGFunctionDefinition); @@ -24981,28 +25209,28 @@ YYLTYPE yylloc; ;} break; - case 506: + case 512: #line 85 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 507: + case 513: #line 89 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 508: + case 514: #line 96 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 510: + case 516: #line 104 "third_party/libpg_query/grammar/statements/create_function.y" { PGFunctionDefinition *n = makeNode(PGFunctionDefinition); @@ -25012,56 +25240,56 @@ YYLTYPE yylloc; ;} break; - case 511: + case 517: #line 114 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 512: + case 518: #line 118 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 515: + case 521: #line 131 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = NIL; ;} break; - case 516: + case 522: #line 135 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = (yyvsp[(2) - (4)].list); ;} break; - case 517: + case 523: #line 139 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 518: + case 524: #line 146 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 519: + case 525: #line 150 "third_party/libpg_query/grammar/statements/create_function.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 520: + case 526: #line 157 "third_party/libpg_query/grammar/statements/create_function.y" { PGFunctionParameter *n = makeNode(PGFunctionParameter); @@ -25072,7 +25300,7 @@ YYLTYPE yylloc; ;} break; - case 521: + case 527: #line 165 "third_party/libpg_query/grammar/statements/create_function.y" { PGFunctionParameter *n = makeNode(PGFunctionParameter); @@ -25083,7 +25311,7 @@ YYLTYPE yylloc; ;} break; - case 522: + case 528: #line 173 "third_party/libpg_query/grammar/statements/create_function.y" { PGFunctionParameter *n = makeNode(PGFunctionParameter); @@ -25094,7 +25322,7 @@ YYLTYPE yylloc; ;} break; - case 523: + case 529: #line 12 "third_party/libpg_query/grammar/statements/update.y" { PGUpdateStmt *n = makeNode(PGUpdateStmt); @@ -25108,7 +25336,7 @@ YYLTYPE yylloc; ;} break; - case 524: + case 530: #line 3 "third_party/libpg_query/grammar/statements/copy.y" { PGCopyStmt *n = makeNode(PGCopyStmt); @@ -25139,7 +25367,7 @@ YYLTYPE yylloc; ;} break; - case 525: + case 531: #line 31 "third_party/libpg_query/grammar/statements/copy.y" { PGCopyStmt *n = makeNode(PGCopyStmt); @@ -25161,7 +25389,7 @@ YYLTYPE yylloc; ;} break; - case 526: + case 532: #line 50 "third_party/libpg_query/grammar/statements/copy.y" { PGCopyDatabaseStmt *n = makeNode(PGCopyDatabaseStmt); @@ -25172,287 +25400,287 @@ YYLTYPE yylloc; ;} break; - case 527: + case 533: #line 61 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.conststr) = NULL; ;} break; - case 528: + case 534: #line 62 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.conststr) = "schema"; ;} break; - case 529: + case 535: #line 63 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.conststr) = "data"; ;} break; - case 530: + case 536: #line 67 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.boolean) = true; ;} break; - case 531: + case 537: #line 68 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.boolean) = false; ;} break; - case 532: + case 538: #line 74 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("delimiter", (PGNode *)makeString((yyvsp[(3) - (3)].str)), (yylsp[(2) - (3)])); ;} break; - case 533: + case 539: #line 77 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = NULL; ;} break; - case 534: + case 540: #line 94 "third_party/libpg_query/grammar/statements/copy.y" {;} break; - case 535: + case 541: #line 95 "third_party/libpg_query/grammar/statements/copy.y" {;} break; - case 536: + case 542: #line 99 "third_party/libpg_query/grammar/statements/copy.y" {;} break; - case 537: + case 543: #line 100 "third_party/libpg_query/grammar/statements/copy.y" {;} break; - case 538: + case 544: #line 105 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.boolean) = true; ;} break; - case 539: + case 545: #line 106 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.boolean) = false; ;} break; - case 540: + case 546: #line 110 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 541: + case 547: #line 111 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 542: + case 548: #line 116 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("oids", NULL, (yylsp[(1) - (2)])); ;} break; - case 543: + case 549: #line 119 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = NULL; ;} break; - case 544: + case 550: #line 124 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].defelt)); ;} break; - case 545: + case 551: #line 125 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.list) = NIL; ;} break; - case 546: + case 552: #line 131 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("format", (PGNode *)makeStringConst("binary", (yylsp[(1) - (1)])), (yylsp[(1) - (1)])); ;} break; - case 547: + case 553: #line 134 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = NULL; ;} break; - case 548: + case 554: #line 140 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("format", (PGNode *)makeStringConst("binary", (yylsp[(1) - (1)])), (yylsp[(1) - (1)])); ;} break; - case 549: + case 555: #line 144 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("oids", NULL, (yylsp[(1) - (1)])); ;} break; - case 550: + case 556: #line 148 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("freeze", NULL, (yylsp[(1) - (1)])); ;} break; - case 551: + case 557: #line 152 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("delimiter", (PGNode *)makeStringConst((yyvsp[(3) - (3)].str), (yylsp[(3) - (3)])), (yylsp[(1) - (3)])); ;} break; - case 552: + case 558: #line 156 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("null", (PGNode *)makeStringConst((yyvsp[(3) - (3)].str), (yylsp[(3) - (3)])), (yylsp[(1) - (3)])); ;} break; - case 553: + case 559: #line 160 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("format", (PGNode *)makeStringConst("csv", (yylsp[(1) - (1)])), (yylsp[(1) - (1)])); ;} break; - case 554: + case 560: #line 164 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("header", NULL, (yylsp[(1) - (1)])); ;} break; - case 555: + case 561: #line 168 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("quote", (PGNode *)makeStringConst((yyvsp[(3) - (3)].str), (yylsp[(3) - (3)])), (yylsp[(1) - (3)])); ;} break; - case 556: + case 562: #line 172 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("escape", (PGNode *)makeStringConst((yyvsp[(3) - (3)].str), (yylsp[(3) - (3)])), (yylsp[(1) - (3)])); ;} break; - case 557: + case 563: #line 176 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("force_quote", (PGNode *)(yyvsp[(3) - (3)].list), (yylsp[(1) - (3)])); ;} break; - case 558: + case 564: #line 180 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("force_quote", (PGNode *)makeNode(PGAStar), (yylsp[(1) - (3)])); ;} break; - case 559: + case 565: #line 184 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("partition_by", (PGNode *)(yyvsp[(3) - (3)].list), (yylsp[(1) - (3)])); ;} break; - case 560: + case 566: #line 188 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("partition_by", (PGNode *)makeNode(PGAStar), (yylsp[(1) - (3)])); ;} break; - case 561: + case 567: #line 192 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("force_not_null", (PGNode *)(yyvsp[(4) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 562: + case 568: #line 196 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("force_null", (PGNode *)(yyvsp[(3) - (3)].list), (yylsp[(1) - (3)])); ;} break; - case 563: + case 569: #line 200 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.defelt) = makeDefElem("encoding", (PGNode *)makeStringConst((yyvsp[(2) - (2)].str), (yylsp[(2) - (2)])), (yylsp[(1) - (2)])); ;} break; - case 564: + case 570: #line 211 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 565: + case 571: #line 212 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.node) = makeStringConst("/dev/stdin", (yylsp[(1) - (1)])); ;} break; - case 566: + case 572: #line 213 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.node) = makeStringConst("/dev/stdout", (yylsp[(1) - (1)])); ;} break; - case 567: + case 573: #line 214 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.node) = makeStringConst(psprintf("%s.%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)), (yylsp[(1) - (3)])); ;} break; - case 568: + case 574: #line 215 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 569: + case 575: #line 216 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.node) = (yyvsp[(2) - (3)].node); ;} break; - case 570: + case 576: #line 217 "third_party/libpg_query/grammar/statements/copy.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 573: + case 579: #line 52 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (3)].node); ;} break; - case 574: + case 580: #line 53 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (3)].node); ;} break; - case 575: + case 581: #line 55 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (3)].node); ;} break; - case 576: + case 582: #line 72 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 577: + case 583: #line 74 "third_party/libpg_query/grammar/statements/select.y" { insertSelectOptions((PGSelectStmt *) (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].list), NIL, @@ -25462,7 +25690,7 @@ YYLTYPE yylloc; ;} break; - case 578: + case 584: #line 81 "third_party/libpg_query/grammar/statements/select.y" { insertSelectOptions((PGSelectStmt *) (yyvsp[(1) - (4)].node), (yyvsp[(2) - (4)].list), (yyvsp[(3) - (4)].list), @@ -25473,7 +25701,7 @@ YYLTYPE yylloc; ;} break; - case 579: + case 585: #line 89 "third_party/libpg_query/grammar/statements/select.y" { insertSelectOptions((PGSelectStmt *) (yyvsp[(1) - (4)].node), (yyvsp[(2) - (4)].list), (yyvsp[(4) - (4)].list), @@ -25484,7 +25712,7 @@ YYLTYPE yylloc; ;} break; - case 580: + case 586: #line 97 "third_party/libpg_query/grammar/statements/select.y" { insertSelectOptions((PGSelectStmt *) (yyvsp[(2) - (2)].node), NULL, NIL, @@ -25495,7 +25723,7 @@ YYLTYPE yylloc; ;} break; - case 581: + case 587: #line 105 "third_party/libpg_query/grammar/statements/select.y" { insertSelectOptions((PGSelectStmt *) (yyvsp[(2) - (3)].node), (yyvsp[(3) - (3)].list), NIL, @@ -25506,7 +25734,7 @@ YYLTYPE yylloc; ;} break; - case 582: + case 588: #line 113 "third_party/libpg_query/grammar/statements/select.y" { insertSelectOptions((PGSelectStmt *) (yyvsp[(2) - (5)].node), (yyvsp[(3) - (5)].list), (yyvsp[(4) - (5)].list), @@ -25517,7 +25745,7 @@ YYLTYPE yylloc; ;} break; - case 583: + case 589: #line 121 "third_party/libpg_query/grammar/statements/select.y" { insertSelectOptions((PGSelectStmt *) (yyvsp[(2) - (5)].node), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list), @@ -25528,24 +25756,24 @@ YYLTYPE yylloc; ;} break; - case 584: + case 590: #line 131 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 585: + case 591: #line 132 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 586: + case 592: #line 160 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 587: + case 593: #line 164 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); @@ -25553,7 +25781,7 @@ YYLTYPE yylloc; ;} break; - case 588: + case 594: #line 175 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = makeNode(PGSelectStmt); @@ -25570,7 +25798,7 @@ YYLTYPE yylloc; ;} break; - case 589: + case 595: #line 191 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = makeNode(PGSelectStmt); @@ -25588,7 +25816,7 @@ YYLTYPE yylloc; ;} break; - case 590: + case 596: #line 208 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = makeNode(PGSelectStmt); @@ -25606,7 +25834,7 @@ YYLTYPE yylloc; ;} break; - case 591: + case 597: #line 226 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = makeNode(PGSelectStmt); @@ -25625,12 +25853,12 @@ YYLTYPE yylloc; ;} break; - case 592: + case 598: #line 241 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 593: + case 599: #line 243 "third_party/libpg_query/grammar/statements/select.y" { /* same as SELECT * FROM relation_expr */ @@ -25652,35 +25880,35 @@ YYLTYPE yylloc; ;} break; - case 594: + case 600: #line 262 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSetOp(PG_SETOP_UNION_BY_NAME, (yyvsp[(3) - (5)].boolean), (yyvsp[(1) - (5)].node), (yyvsp[(5) - (5)].node)); ;} break; - case 595: + case 601: #line 266 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSetOp(PG_SETOP_UNION, (yyvsp[(3) - (4)].boolean), (yyvsp[(1) - (4)].node), (yyvsp[(4) - (4)].node)); ;} break; - case 596: + case 602: #line 270 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSetOp(PG_SETOP_INTERSECT, (yyvsp[(3) - (4)].boolean), (yyvsp[(1) - (4)].node), (yyvsp[(4) - (4)].node)); ;} break; - case 597: + case 603: #line 274 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSetOp(PG_SETOP_EXCEPT, (yyvsp[(3) - (4)].boolean), (yyvsp[(1) - (4)].node), (yyvsp[(4) - (4)].node)); ;} break; - case 598: + case 604: #line 278 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *res = makeNode(PGSelectStmt); @@ -25693,7 +25921,7 @@ YYLTYPE yylloc; ;} break; - case 599: + case 605: #line 288 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *res = makeNode(PGSelectStmt); @@ -25707,7 +25935,7 @@ YYLTYPE yylloc; ;} break; - case 600: + case 606: #line 299 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *res = makeNode(PGSelectStmt); @@ -25720,7 +25948,7 @@ YYLTYPE yylloc; ;} break; - case 601: + case 607: #line 309 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *res = makeNode(PGSelectStmt); @@ -25732,7 +25960,7 @@ YYLTYPE yylloc; ;} break; - case 602: + case 608: #line 318 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *res = makeNode(PGSelectStmt); @@ -25746,7 +25974,7 @@ YYLTYPE yylloc; ;} break; - case 603: + case 609: #line 329 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *res = makeNode(PGSelectStmt); @@ -25760,7 +25988,7 @@ YYLTYPE yylloc; ;} break; - case 604: + case 610: #line 340 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *res = makeNode(PGSelectStmt); @@ -25775,7 +26003,7 @@ YYLTYPE yylloc; ;} break; - case 605: + case 611: #line 352 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *res = makeNode(PGSelectStmt); @@ -25793,7 +26021,7 @@ YYLTYPE yylloc; ;} break; - case 606: + case 612: #line 367 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *res = makeNode(PGSelectStmt); @@ -25811,7 +26039,7 @@ YYLTYPE yylloc; ;} break; - case 613: + case 619: #line 397 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); @@ -25820,7 +26048,7 @@ YYLTYPE yylloc; ;} break; - case 614: + case 620: #line 403 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); @@ -25830,32 +26058,32 @@ YYLTYPE yylloc; ;} break; - case 615: + case 621: #line 409 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 616: + case 622: #line 413 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 617: + case 623: #line 414 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 618: + case 624: #line 418 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 619: + case 625: #line 419 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 620: + case 626: #line 434 "third_party/libpg_query/grammar/statements/select.y" { (yyval.with) = makeNode(PGWithClause); @@ -25865,7 +26093,7 @@ YYLTYPE yylloc; ;} break; - case 621: + case 627: #line 441 "third_party/libpg_query/grammar/statements/select.y" { (yyval.with) = makeNode(PGWithClause); @@ -25875,7 +26103,7 @@ YYLTYPE yylloc; ;} break; - case 622: + case 628: #line 448 "third_party/libpg_query/grammar/statements/select.y" { (yyval.with) = makeNode(PGWithClause); @@ -25885,17 +26113,17 @@ YYLTYPE yylloc; ;} break; - case 623: + case 629: #line 457 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 624: + case 630: #line 458 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 625: + case 631: #line 462 "third_party/libpg_query/grammar/statements/select.y" { PGCommonTableExpr *n = makeNode(PGCommonTableExpr); @@ -25909,52 +26137,52 @@ YYLTYPE yylloc; ;} break; - case 626: + case 632: #line 475 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(4) - (5)].list); ;} break; - case 627: + case 633: #line 476 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(NIL); ;} break; - case 628: + case 634: #line 480 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 629: + case 635: #line 481 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 630: + case 636: #line 485 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 631: + case 637: #line 486 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 632: + case 638: #line 490 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ctematerialize) = PGCTEMaterializeAlways; ;} break; - case 633: + case 639: #line 491 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ctematerialize) = PGCTEMaterializeNever; ;} break; - case 634: + case 640: #line 492 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ctematerialize) = PGCTEMaterializeDefault; ;} break; - case 635: + case 641: #line 497 "third_party/libpg_query/grammar/statements/select.y" { (yyval.into) = makeNode(PGIntoClause); @@ -25967,12 +26195,12 @@ YYLTYPE yylloc; ;} break; - case 636: + case 642: #line 507 "third_party/libpg_query/grammar/statements/select.y" { (yyval.into) = NULL; ;} break; - case 637: + case 643: #line 516 "third_party/libpg_query/grammar/statements/select.y" { (yyval.range) = (yyvsp[(3) - (3)].range); @@ -25980,7 +26208,7 @@ YYLTYPE yylloc; ;} break; - case 638: + case 644: #line 521 "third_party/libpg_query/grammar/statements/select.y" { (yyval.range) = (yyvsp[(3) - (3)].range); @@ -25988,7 +26216,7 @@ YYLTYPE yylloc; ;} break; - case 639: + case 645: #line 526 "third_party/libpg_query/grammar/statements/select.y" { (yyval.range) = (yyvsp[(4) - (4)].range); @@ -25996,7 +26224,7 @@ YYLTYPE yylloc; ;} break; - case 640: + case 646: #line 531 "third_party/libpg_query/grammar/statements/select.y" { (yyval.range) = (yyvsp[(4) - (4)].range); @@ -26004,7 +26232,7 @@ YYLTYPE yylloc; ;} break; - case 641: + case 647: #line 536 "third_party/libpg_query/grammar/statements/select.y" { ereport(PGWARNING, @@ -26015,7 +26243,7 @@ YYLTYPE yylloc; ;} break; - case 642: + case 648: #line 544 "third_party/libpg_query/grammar/statements/select.y" { ereport(PGWARNING, @@ -26026,7 +26254,7 @@ YYLTYPE yylloc; ;} break; - case 643: + case 649: #line 552 "third_party/libpg_query/grammar/statements/select.y" { (yyval.range) = (yyvsp[(3) - (3)].range); @@ -26034,7 +26262,7 @@ YYLTYPE yylloc; ;} break; - case 644: + case 650: #line 557 "third_party/libpg_query/grammar/statements/select.y" { (yyval.range) = (yyvsp[(2) - (2)].range); @@ -26042,7 +26270,7 @@ YYLTYPE yylloc; ;} break; - case 645: + case 651: #line 562 "third_party/libpg_query/grammar/statements/select.y" { (yyval.range) = (yyvsp[(1) - (1)].range); @@ -26050,87 +26278,87 @@ YYLTYPE yylloc; ;} break; - case 646: + case 652: #line 568 "third_party/libpg_query/grammar/statements/select.y" {;} break; - case 647: + case 653: #line 569 "third_party/libpg_query/grammar/statements/select.y" {;} break; - case 648: + case 654: #line 573 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 649: + case 655: #line 574 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 650: + case 656: #line 575 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 651: + case 657: #line 579 "third_party/libpg_query/grammar/statements/select.y" { ;} break; - case 652: + case 658: #line 586 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(NIL); ;} break; - case 653: + case 659: #line 587 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(4) - (5)].list); ;} break; - case 654: + case 660: #line 591 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL;;} break; - case 655: + case 661: #line 592 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 656: + case 662: #line 596 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ignorenulls) = PG_IGNORE_NULLS;;} break; - case 657: + case 663: #line 597 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ignorenulls) = PG_RESPECT_NULLS;;} break; - case 658: + case 664: #line 598 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ignorenulls) = PG_DEFAULT_NULLS; ;} break; - case 659: + case 665: #line 602 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list);;} break; - case 660: + case 666: #line 603 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 661: + case 667: #line 607 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 662: + case 668: #line 609 "third_party/libpg_query/grammar/statements/select.y" { PGSortBy *sort = makeNode(PGSortBy); @@ -26146,17 +26374,17 @@ YYLTYPE yylloc; ;} break; - case 663: + case 669: #line 624 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].sortby)); ;} break; - case 664: + case 670: #line 625 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].sortby)); ;} break; - case 665: + case 671: #line 629 "third_party/libpg_query/grammar/statements/select.y" { (yyval.sortby) = makeNode(PGSortBy); @@ -26168,7 +26396,7 @@ YYLTYPE yylloc; ;} break; - case 666: + case 672: #line 638 "third_party/libpg_query/grammar/statements/select.y" { (yyval.sortby) = makeNode(PGSortBy); @@ -26180,72 +26408,72 @@ YYLTYPE yylloc; ;} break; - case 667: + case 673: #line 648 "third_party/libpg_query/grammar/statements/select.y" { (yyval.sortorder) = PG_SORTBY_ASC; ;} break; - case 668: + case 674: #line 649 "third_party/libpg_query/grammar/statements/select.y" { (yyval.sortorder) = PG_SORTBY_DESC; ;} break; - case 669: + case 675: #line 650 "third_party/libpg_query/grammar/statements/select.y" { (yyval.sortorder) = PG_SORTBY_DEFAULT; ;} break; - case 670: + case 676: #line 653 "third_party/libpg_query/grammar/statements/select.y" { (yyval.nullorder) = PG_SORTBY_NULLS_FIRST; ;} break; - case 671: + case 677: #line 654 "third_party/libpg_query/grammar/statements/select.y" { (yyval.nullorder) = PG_SORTBY_NULLS_LAST; ;} break; - case 672: + case 678: #line 655 "third_party/libpg_query/grammar/statements/select.y" { (yyval.nullorder) = PG_SORTBY_NULLS_DEFAULT; ;} break; - case 673: + case 679: #line 659 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make3((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].node), NULL); ;} break; - case 674: + case 680: #line 660 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make3((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].node)); ;} break; - case 675: + case 681: #line 661 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make3(NULL, (yyvsp[(1) - (1)].node), NULL); ;} break; - case 676: + case 682: #line 662 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make3((yyvsp[(1) - (1)].node), NULL, (yyvsp[(1) - (1)].node)); ;} break; - case 677: + case 683: #line 666 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 678: + case 684: #line 667 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make3(NULL,NULL,NULL); ;} break; - case 679: + case 685: #line 672 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 680: + case 686: #line 674 "third_party/libpg_query/grammar/statements/select.y" { /* Disabled because it was too confusing, bjm 2002-02-18 */ @@ -26257,91 +26485,91 @@ YYLTYPE yylloc; ;} break; - case 681: + case 687: #line 690 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(3) - (5)].node); ;} break; - case 682: + case 688: #line 692 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntConst(1, -1); ;} break; - case 683: + case 689: #line 697 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 684: + case 690: #line 700 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (3)].node); ;} break; - case 685: + case 691: #line 705 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 686: + case 692: #line 709 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival), (yylsp[(1) - (1)])); ;} break; - case 688: + case 694: #line 720 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSampleSize((yyvsp[(1) - (2)].node), true); ;} break; - case 689: + case 695: #line 724 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSampleSize((yyvsp[(1) - (2)].node), true); ;} break; - case 690: + case 696: #line 728 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSampleSize((yyvsp[(1) - (1)].node), false); ;} break; - case 691: + case 697: #line 732 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSampleSize((yyvsp[(1) - (2)].node), false); ;} break; - case 692: + case 698: #line 739 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(3) - (3)].node); ;} break; - case 693: + case 699: #line 743 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 694: + case 700: #line 750 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 695: + case 701: #line 751 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = NULL; ;} break; - case 696: + case 702: #line 756 "third_party/libpg_query/grammar/statements/select.y" { int seed = (yyvsp[(5) - (5)].ival); @@ -26349,21 +26577,21 @@ YYLTYPE yylloc; ;} break; - case 697: + case 703: #line 761 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSampleOptions((yyvsp[(1) - (1)].node), NULL, NULL, (yylsp[(1) - (1)])); ;} break; - case 698: + case 704: #line 765 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSampleOptions((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].str), NULL, (yylsp[(1) - (4)])); ;} break; - case 699: + case 705: #line 769 "third_party/libpg_query/grammar/statements/select.y" { int seed = (yyvsp[(5) - (6)].ival); @@ -26371,44 +26599,44 @@ YYLTYPE yylloc; ;} break; - case 700: + case 706: #line 777 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 701: + case 707: #line 783 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 702: + case 708: #line 784 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 703: + case 709: #line 789 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = (yyvsp[(3) - (4)].ival); ;} break; - case 704: + case 710: #line 790 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = -1; ;} break; - case 705: + case 711: #line 795 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "TIMESTAMP"; ;} break; - case 706: + case 712: #line 796 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "VERSION"; ;} break; - case 707: + case 713: #line 801 "third_party/libpg_query/grammar/statements/select.y" { PGAtClause *n = makeNode(PGAtClause); @@ -26418,22 +26646,22 @@ YYLTYPE yylloc; ;} break; - case 708: + case 714: #line 810 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(3) - (4)].node); ;} break; - case 709: + case 715: #line 811 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 710: + case 716: #line 816 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 711: + case 717: #line 818 "third_party/libpg_query/grammar/statements/select.y" { /* LIMIT ALL is represented as a NULL constant */ @@ -26441,77 +26669,77 @@ YYLTYPE yylloc; ;} break; - case 712: + case 718: #line 823 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeLimitPercent((yyvsp[(1) - (2)].node)); ;} break; - case 713: + case 719: #line 825 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeLimitPercent(makeFloatConst((yyvsp[(1) - (2)].str),(yylsp[(1) - (2)]))); ;} break; - case 714: + case 720: #line 827 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeLimitPercent(makeIntConst((yyvsp[(1) - (2)].ival),(yylsp[(1) - (2)]))); ;} break; - case 715: + case 721: #line 831 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 716: + case 722: #line 851 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 717: + case 723: #line 853 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 718: + case 724: #line 855 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 719: + case 725: #line 859 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival),(yylsp[(1) - (1)])); ;} break; - case 720: + case 726: #line 860 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str),(yylsp[(1) - (1)])); ;} break; - case 721: + case 727: #line 864 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 722: + case 728: #line 865 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 723: + case 729: #line 868 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 724: + case 730: #line 869 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 725: + case 731: #line 894 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 726: + case 732: #line 896 "third_party/libpg_query/grammar/statements/select.y" { PGNode *node = (PGNode *) makeGroupingSet(GROUPING_SET_ALL, NIL, (yylsp[(3) - (3)])); @@ -26519,145 +26747,145 @@ YYLTYPE yylloc; ;} break; - case 727: + case 733: #line 900 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 728: + case 734: #line 904 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 729: + case 735: #line 905 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list),(yyvsp[(3) - (3)].node)); ;} break; - case 730: + case 736: #line 909 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 731: + case 737: #line 910 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 732: + case 738: #line 914 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 733: + case 739: #line 915 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 734: + case 740: #line 916 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 735: + case 741: #line 917 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 736: + case 742: #line 918 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 737: + case 743: #line 923 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_EMPTY, NIL, (yylsp[(1) - (2)])); ;} break; - case 738: + case 744: #line 936 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_ROLLUP, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 739: + case 745: #line 943 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_CUBE, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 740: + case 746: #line 950 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_SETS, (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); ;} break; - case 741: + case 747: #line 956 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 742: + case 748: #line 957 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 743: + case 749: #line 961 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 744: + case 750: #line 962 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 745: + case 751: #line 966 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 746: + case 752: #line 967 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 747: + case 753: #line 971 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 748: + case 754: #line 972 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 749: + case 755: #line 976 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 750: + case 756: #line 977 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 751: + case 757: #line 981 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 752: + case 758: #line 982 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 753: + case 759: #line 987 "third_party/libpg_query/grammar/statements/select.y" { PGLockingClause *n = makeNode(PGLockingClause); @@ -26668,52 +26896,52 @@ YYLTYPE yylloc; ;} break; - case 754: + case 760: #line 997 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = LCS_FORUPDATE; ;} break; - case 755: + case 761: #line 998 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = PG_LCS_FORNOKEYUPDATE; ;} break; - case 756: + case 762: #line 999 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = PG_LCS_FORSHARE; ;} break; - case 757: + case 763: #line 1000 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = PG_LCS_FORKEYSHARE; ;} break; - case 758: + case 764: #line 1004 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 759: + case 765: #line 1005 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 760: + case 766: #line 1010 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockwaitpolicy) = LockWaitError; ;} break; - case 761: + case 767: #line 1011 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockwaitpolicy) = PGLockWaitSkip; ;} break; - case 762: + case 768: #line 1012 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockwaitpolicy) = PGLockWaitBlock; ;} break; - case 763: + case 769: #line 1022 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = makeNode(PGSelectStmt); @@ -26722,7 +26950,7 @@ YYLTYPE yylloc; ;} break; - case 764: + case 770: #line 1028 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = (PGSelectStmt *) (yyvsp[(1) - (5)].node); @@ -26731,47 +26959,47 @@ YYLTYPE yylloc; ;} break; - case 765: + case 771: #line 1036 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 766: + case 772: #line 1037 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (2)].node); ;} break; - case 767: + case 773: #line 1050 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 768: + case 774: #line 1051 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 769: + case 775: #line 1055 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 770: + case 776: #line 1056 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 771: + case 777: #line 1060 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 772: + case 778: #line 1061 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 773: + case 779: #line 1066 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); @@ -26779,7 +27007,7 @@ YYLTYPE yylloc; ;} break; - case 774: + case 780: #line 1077 "third_party/libpg_query/grammar/statements/select.y" { (yyvsp[(1) - (4)].range)->at_clause = (yyvsp[(3) - (4)].node); @@ -26789,7 +27017,7 @@ YYLTYPE yylloc; ;} break; - case 775: + case 781: #line 1084 "third_party/libpg_query/grammar/statements/select.y" { (yyvsp[(2) - (4)].range)->at_clause = (yyvsp[(3) - (4)].node); @@ -26799,7 +27027,7 @@ YYLTYPE yylloc; ;} break; - case 776: + case 782: #line 1091 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = (PGRangeFunction *) (yyvsp[(1) - (3)].node); @@ -26810,7 +27038,7 @@ YYLTYPE yylloc; ;} break; - case 777: + case 783: #line 1099 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = (PGRangeFunction *) (yyvsp[(2) - (3)].node); @@ -26820,7 +27048,7 @@ YYLTYPE yylloc; ;} break; - case 778: + case 784: #line 1107 "third_party/libpg_query/grammar/statements/select.y" { PGRangeSubselect *n = makeNode(PGRangeSubselect); @@ -26832,7 +27060,7 @@ YYLTYPE yylloc; ;} break; - case 779: + case 785: #line 1117 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = (PGRangeFunction *) (yyvsp[(2) - (3)].node); @@ -26843,7 +27071,7 @@ YYLTYPE yylloc; ;} break; - case 780: + case 786: #line 1125 "third_party/libpg_query/grammar/statements/select.y" { PGRangeSubselect *n = makeNode(PGRangeSubselect); @@ -26855,7 +27083,7 @@ YYLTYPE yylloc; ;} break; - case 781: + case 787: #line 1134 "third_party/libpg_query/grammar/statements/select.y" { PGRangeSubselect *n = makeNode(PGRangeSubselect); @@ -26867,7 +27095,7 @@ YYLTYPE yylloc; ;} break; - case 782: + case 788: #line 1143 "third_party/libpg_query/grammar/statements/select.y" { PGRangeSubselect *n = makeNode(PGRangeSubselect); @@ -26879,14 +27107,14 @@ YYLTYPE yylloc; ;} break; - case 783: + case 789: #line 1152 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) (yyvsp[(1) - (1)].jexpr); ;} break; - case 784: + case 790: #line 1156 "third_party/libpg_query/grammar/statements/select.y" { (yyvsp[(2) - (4)].jexpr)->alias = (yyvsp[(4) - (4)].alias); @@ -26894,7 +27122,7 @@ YYLTYPE yylloc; ;} break; - case 785: + case 791: #line 1161 "third_party/libpg_query/grammar/statements/select.y" { (yyvsp[(3) - (4)].jexpr)->alias = (yyvsp[(1) - (4)].alias); @@ -26902,7 +27130,7 @@ YYLTYPE yylloc; ;} break; - case 786: + case 792: #line 1166 "third_party/libpg_query/grammar/statements/select.y" { PGPivotExpr *n = makeNode(PGPivotExpr); @@ -26916,7 +27144,7 @@ YYLTYPE yylloc; ;} break; - case 787: + case 793: #line 1177 "third_party/libpg_query/grammar/statements/select.y" { PGPivotExpr *n = makeNode(PGPivotExpr); @@ -26930,32 +27158,32 @@ YYLTYPE yylloc; ;} break; - case 788: + case 794: #line 1190 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 789: + case 795: #line 1191 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 790: + case 796: #line 1194 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 791: + case 797: #line 1195 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 792: + case 798: #line 1196 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 793: + case 799: #line 1200 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); @@ -26965,7 +27193,7 @@ YYLTYPE yylloc; ;} break; - case 794: + case 800: #line 1208 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); @@ -26975,22 +27203,22 @@ YYLTYPE yylloc; ;} break; - case 795: + case 801: #line 1217 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 796: + case 802: #line 1218 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 797: + case 803: #line 1219 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 798: + case 804: #line 1223 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); @@ -27000,7 +27228,7 @@ YYLTYPE yylloc; ;} break; - case 799: + case 805: #line 1231 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); @@ -27010,31 +27238,31 @@ YYLTYPE yylloc; ;} break; - case 800: + case 806: #line 1240 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 801: + case 807: #line 1244 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 802: + case 808: #line 1250 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 803: + case 809: #line 1251 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 804: + case 810: #line 1256 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); @@ -27044,28 +27272,28 @@ YYLTYPE yylloc; ;} break; - case 805: + case 811: #line 1265 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 806: + case 812: #line 1269 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 807: + case 813: #line 1294 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jexpr) = (yyvsp[(2) - (3)].jexpr); ;} break; - case 808: + case 814: #line 1298 "third_party/libpg_query/grammar/statements/select.y" { /* CROSS JOIN is same as unqualified inner join */ @@ -27081,7 +27309,7 @@ YYLTYPE yylloc; ;} break; - case 809: + case 815: #line 1311 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); @@ -27098,7 +27326,7 @@ YYLTYPE yylloc; ;} break; - case 810: + case 816: #line 1325 "third_party/libpg_query/grammar/statements/select.y" { /* letting join_type reduce to empty doesn't work */ @@ -27116,7 +27344,7 @@ YYLTYPE yylloc; ;} break; - case 811: + case 817: #line 1340 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); @@ -27131,7 +27359,7 @@ YYLTYPE yylloc; ;} break; - case 812: + case 818: #line 1352 "third_party/libpg_query/grammar/statements/select.y" { /* letting join_type reduce to empty doesn't work */ @@ -27147,7 +27375,7 @@ YYLTYPE yylloc; ;} break; - case 813: + case 819: #line 1365 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); @@ -27164,7 +27392,7 @@ YYLTYPE yylloc; ;} break; - case 814: + case 820: #line 1379 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); @@ -27181,7 +27409,7 @@ YYLTYPE yylloc; ;} break; - case 815: + case 821: #line 1393 "third_party/libpg_query/grammar/statements/select.y" { /* POSITIONAL JOIN is a coordinated scan */ @@ -27197,7 +27425,7 @@ YYLTYPE yylloc; ;} break; - case 816: + case 822: #line 1406 "third_party/libpg_query/grammar/statements/select.y" { /* ANTI JOIN is a filter */ @@ -27215,7 +27443,7 @@ YYLTYPE yylloc; ;} break; - case 817: + case 823: #line 1421 "third_party/libpg_query/grammar/statements/select.y" { /* SEMI JOIN is also a filter */ @@ -27234,7 +27462,7 @@ YYLTYPE yylloc; ;} break; - case 818: + case 824: #line 1440 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); @@ -27243,7 +27471,7 @@ YYLTYPE yylloc; ;} break; - case 819: + case 825: #line 1446 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); @@ -27251,7 +27479,7 @@ YYLTYPE yylloc; ;} break; - case 820: + case 826: #line 1451 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); @@ -27260,7 +27488,7 @@ YYLTYPE yylloc; ;} break; - case 821: + case 827: #line 1457 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); @@ -27268,31 +27496,31 @@ YYLTYPE yylloc; ;} break; - case 822: + case 828: #line 1463 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = (yyvsp[(1) - (1)].alias); ;} break; - case 823: + case 829: #line 1464 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = NULL; ;} break; - case 824: + case 830: #line 1473 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (1)].alias), NIL); ;} break; - case 825: + case 831: #line 1477 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(NULL, (yyvsp[(3) - (4)].list)); ;} break; - case 826: + case 832: #line 1481 "third_party/libpg_query/grammar/statements/select.y" { PGAlias *a = makeNode(PGAlias); @@ -27301,7 +27529,7 @@ YYLTYPE yylloc; ;} break; - case 827: + case 833: #line 1487 "third_party/libpg_query/grammar/statements/select.y" { PGAlias *a = makeNode(PGAlias); @@ -27310,64 +27538,64 @@ YYLTYPE yylloc; ;} break; - case 828: + case 834: #line 1493 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(NULL, NIL); ;} break; - case 829: + case 835: #line 1498 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_FULL; ;} break; - case 830: + case 836: #line 1499 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_LEFT; ;} break; - case 831: + case 837: #line 1500 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_RIGHT; ;} break; - case 832: + case 838: #line 1501 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_SEMI; ;} break; - case 833: + case 839: #line 1502 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_ANTI; ;} break; - case 834: + case 840: #line 1503 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_INNER; ;} break; - case 835: + case 841: #line 1507 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 836: + case 842: #line 1508 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 837: + case 843: #line 1520 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) (yyvsp[(3) - (4)].list); ;} break; - case 838: + case 844: #line 1521 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 839: + case 845: #line 1527 "third_party/libpg_query/grammar/statements/select.y" { /* inheritance query, implicitly */ @@ -27377,7 +27605,7 @@ YYLTYPE yylloc; ;} break; - case 840: + case 846: #line 1534 "third_party/libpg_query/grammar/statements/select.y" { /* inheritance query, explicitly */ @@ -27387,7 +27615,7 @@ YYLTYPE yylloc; ;} break; - case 841: + case 847: #line 1541 "third_party/libpg_query/grammar/statements/select.y" { /* no inheritance */ @@ -27397,7 +27625,7 @@ YYLTYPE yylloc; ;} break; - case 842: + case 848: #line 1548 "third_party/libpg_query/grammar/statements/select.y" { /* no inheritance, SQL99-style syntax */ @@ -27407,7 +27635,7 @@ YYLTYPE yylloc; ;} break; - case 843: + case 849: #line 1580 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = makeNode(PGRangeFunction); @@ -27421,7 +27649,7 @@ YYLTYPE yylloc; ;} break; - case 844: + case 850: #line 1591 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = makeNode(PGRangeFunction); @@ -27435,66 +27663,66 @@ YYLTYPE yylloc; ;} break; - case 845: + case 851: #line 1604 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].list)); ;} break; - case 846: + case 852: #line 1608 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 847: + case 853: #line 1609 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 848: + case 854: #line 1612 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 849: + case 855: #line 1613 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 850: + case 856: #line 1616 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 851: + case 857: #line 1617 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 852: + case 858: #line 1622 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 853: + case 859: #line 1623 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 854: + case 860: #line 1629 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 855: + case 861: #line 1633 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 856: + case 862: #line 1639 "third_party/libpg_query/grammar/statements/select.y" { PGColumnDef *n = makeNode(PGColumnDef); @@ -27515,7 +27743,7 @@ YYLTYPE yylloc; ;} break; - case 857: + case 863: #line 1660 "third_party/libpg_query/grammar/statements/select.y" { PGCollateClause *n = makeNode(PGCollateClause); @@ -27526,36 +27754,36 @@ YYLTYPE yylloc; ;} break; - case 858: + case 864: #line 1667 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 859: + case 865: #line 1681 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(list_make2(makeString((yyvsp[(1) - (2)].str)), (yyvsp[(2) - (2)].typnam))); ;} break; - case 860: + case 866: #line 1684 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (4)].list), list_make2(makeString((yyvsp[(3) - (4)].str)), (yyvsp[(4) - (4)].typnam))); ;} break; - case 863: + case 869: #line 1691 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 864: + case 870: #line 1692 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = NULL; ;} break; - case 865: + case 871: #line 1695 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); @@ -27563,7 +27791,7 @@ YYLTYPE yylloc; ;} break; - case 866: + case 872: #line 1700 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (3)].typnam); @@ -27572,7 +27800,7 @@ YYLTYPE yylloc; ;} break; - case 867: + case 873: #line 1707 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (5)].typnam); @@ -27580,8 +27808,16 @@ YYLTYPE yylloc; ;} break; - case 868: + case 874: #line 1712 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.typnam) = makeTypeNameFromNameList((yyvsp[(1) - (5)].list)); + (yyval.typnam)->arrayBounds = list_make1(makeInteger((yyvsp[(4) - (5)].ival))); + ;} + break; + + case 875: +#line 1717 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (6)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger((yyvsp[(5) - (6)].ival))); @@ -27589,16 +27825,33 @@ YYLTYPE yylloc; ;} break; - case 869: -#line 1718 "third_party/libpg_query/grammar/statements/select.y" + case 876: +#line 1723 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.typnam) = makeTypeNameFromNameList((yyvsp[(2) - (6)].list)); + (yyval.typnam)->arrayBounds = list_make1(makeInteger((yyvsp[(5) - (6)].ival))); + (yyval.typnam)->setof = true; + ;} + break; + + case 877: +#line 1729 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); ;} break; - case 870: -#line 1723 "third_party/libpg_query/grammar/statements/select.y" + case 878: +#line 1734 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.typnam) = makeTypeNameFromNameList((yyvsp[(1) - (2)].list)); + (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); + ;} + break; + + case 879: +#line 1739 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (3)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); @@ -27606,16 +27859,25 @@ YYLTYPE yylloc; ;} break; - case 871: -#line 1729 "third_party/libpg_query/grammar/statements/select.y" + case 880: +#line 1745 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.typnam) = makeTypeNameFromNameList((yyvsp[(2) - (3)].list)); + (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); + (yyval.typnam)->setof = true; + ;} + break; + + case 881: +#line 1751 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = makeTypeNameFromNameList((yyvsp[(1) - (2)].list)); (yyval.typnam)->arrayBounds = (yyvsp[(2) - (2)].list); ;} break; - case 872: -#line 1734 "third_party/libpg_query/grammar/statements/select.y" + case 882: +#line 1756 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("struct"); (yyval.typnam)->arrayBounds = (yyvsp[(5) - (5)].list); @@ -27624,8 +27886,8 @@ YYLTYPE yylloc; ;} break; - case 873: -#line 1741 "third_party/libpg_query/grammar/statements/select.y" + case 883: +#line 1763 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("map"); (yyval.typnam)->arrayBounds = (yyvsp[(5) - (5)].list); @@ -27634,8 +27896,8 @@ YYLTYPE yylloc; ;} break; - case 874: -#line 1748 "third_party/libpg_query/grammar/statements/select.y" + case 884: +#line 1770 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("union"); (yyval.typnam)->arrayBounds = (yyvsp[(5) - (5)].list); @@ -27644,66 +27906,66 @@ YYLTYPE yylloc; ;} break; - case 875: -#line 1757 "third_party/libpg_query/grammar/statements/select.y" + case 885: +#line 1779 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(makeString((yyvsp[(1) - (3)].str)), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 876: -#line 1758 "third_party/libpg_query/grammar/statements/select.y" + case 886: +#line 1780 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 877: -#line 1763 "third_party/libpg_query/grammar/statements/select.y" + case 887: +#line 1785 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeInteger(-1)); ;} break; - case 878: -#line 1765 "third_party/libpg_query/grammar/statements/select.y" + case 888: +#line 1787 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (4)].list), makeInteger((yyvsp[(3) - (4)].ival))); ;} break; - case 879: -#line 1767 "third_party/libpg_query/grammar/statements/select.y" + case 889: +#line 1789 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 880: -#line 1771 "third_party/libpg_query/grammar/statements/select.y" + case 890: +#line 1793 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 881: -#line 1772 "third_party/libpg_query/grammar/statements/select.y" + case 891: +#line 1794 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 882: -#line 1773 "third_party/libpg_query/grammar/statements/select.y" + case 892: +#line 1795 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 883: -#line 1774 "third_party/libpg_query/grammar/statements/select.y" + case 893: +#line 1796 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 884: -#line 1775 "third_party/libpg_query/grammar/statements/select.y" + case 894: +#line 1797 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 885: -#line 1777 "third_party/libpg_query/grammar/statements/select.y" + case 895: +#line 1799 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); ;} break; - case 886: -#line 1782 "third_party/libpg_query/grammar/statements/select.y" + case 896: +#line 1804 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (4)].typnam); (yyval.typnam)->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), @@ -27711,28 +27973,28 @@ YYLTYPE yylloc; ;} break; - case 887: -#line 1801 "third_party/libpg_query/grammar/statements/select.y" + case 897: +#line 1823 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 888: -#line 1802 "third_party/libpg_query/grammar/statements/select.y" + case 898: +#line 1824 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 889: -#line 1803 "third_party/libpg_query/grammar/statements/select.y" + case 899: +#line 1825 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 890: -#line 1804 "third_party/libpg_query/grammar/statements/select.y" + case 900: +#line 1826 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 891: -#line 1816 "third_party/libpg_query/grammar/statements/select.y" + case 901: +#line 1838 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = makeTypeName((yyvsp[(1) - (2)].str)); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -27740,74 +28002,74 @@ YYLTYPE yylloc; ;} break; - case 892: -#line 1829 "third_party/libpg_query/grammar/statements/select.y" + case 902: +#line 1851 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 893: -#line 1830 "third_party/libpg_query/grammar/statements/select.y" + case 903: +#line 1852 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 894: -#line 1837 "third_party/libpg_query/grammar/statements/select.y" + case 904: +#line 1859 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 895: -#line 1842 "third_party/libpg_query/grammar/statements/select.y" + case 905: +#line 1864 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 896: -#line 1847 "third_party/libpg_query/grammar/statements/select.y" + case 906: +#line 1869 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int2"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 897: -#line 1852 "third_party/libpg_query/grammar/statements/select.y" + case 907: +#line 1874 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int8"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 898: -#line 1857 "third_party/libpg_query/grammar/statements/select.y" + case 908: +#line 1879 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("float4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 899: -#line 1862 "third_party/libpg_query/grammar/statements/select.y" + case 909: +#line 1884 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (2)].typnam); (yyval.typnam)->location = (yylsp[(1) - (2)]); ;} break; - case 900: -#line 1867 "third_party/libpg_query/grammar/statements/select.y" + case 910: +#line 1889 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("float8"); (yyval.typnam)->location = (yylsp[(1) - (2)]); ;} break; - case 901: -#line 1872 "third_party/libpg_query/grammar/statements/select.y" + case 911: +#line 1894 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -27815,8 +28077,8 @@ YYLTYPE yylloc; ;} break; - case 902: -#line 1878 "third_party/libpg_query/grammar/statements/select.y" + case 912: +#line 1900 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -27824,8 +28086,8 @@ YYLTYPE yylloc; ;} break; - case 903: -#line 1884 "third_party/libpg_query/grammar/statements/select.y" + case 913: +#line 1906 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -27833,16 +28095,16 @@ YYLTYPE yylloc; ;} break; - case 904: -#line 1890 "third_party/libpg_query/grammar/statements/select.y" + case 914: +#line 1912 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("bool"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 905: -#line 1897 "third_party/libpg_query/grammar/statements/select.y" + case 915: +#line 1919 "third_party/libpg_query/grammar/statements/select.y" { /* * Check FLOAT() precision limits assuming IEEE floating @@ -27865,44 +28127,44 @@ YYLTYPE yylloc; ;} break; - case 906: -#line 1918 "third_party/libpg_query/grammar/statements/select.y" + case 916: +#line 1940 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("float4"); ;} break; - case 907: -#line 1928 "third_party/libpg_query/grammar/statements/select.y" + case 917: +#line 1950 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 908: -#line 1932 "third_party/libpg_query/grammar/statements/select.y" + case 918: +#line 1954 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 909: -#line 1940 "third_party/libpg_query/grammar/statements/select.y" + case 919: +#line 1962 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 910: -#line 1944 "third_party/libpg_query/grammar/statements/select.y" + case 920: +#line 1966 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); (yyval.typnam)->typmods = NIL; ;} break; - case 911: -#line 1952 "third_party/libpg_query/grammar/statements/select.y" + case 921: +#line 1974 "third_party/libpg_query/grammar/statements/select.y" { const char *typname; @@ -27913,8 +28175,8 @@ YYLTYPE yylloc; ;} break; - case 912: -#line 1964 "third_party/libpg_query/grammar/statements/select.y" + case 922: +#line 1986 "third_party/libpg_query/grammar/statements/select.y" { /* bit defaults to bit(1), varbit to no limit */ if ((yyvsp[(2) - (2)].boolean)) @@ -27930,29 +28192,29 @@ YYLTYPE yylloc; ;} break; - case 913: -#line 1985 "third_party/libpg_query/grammar/statements/select.y" + case 923: +#line 2007 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 914: -#line 1989 "third_party/libpg_query/grammar/statements/select.y" + case 924: +#line 2011 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 915: -#line 1995 "third_party/libpg_query/grammar/statements/select.y" + case 925: +#line 2017 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 916: -#line 1999 "third_party/libpg_query/grammar/statements/select.y" + case 926: +#line 2021 "third_party/libpg_query/grammar/statements/select.y" { /* Length was not specified so allow to be unrestricted. * This handles problems with fixed-length (bpchar) strings @@ -27965,8 +28227,8 @@ YYLTYPE yylloc; ;} break; - case 917: -#line 2012 "third_party/libpg_query/grammar/statements/select.y" + case 927: +#line 2034 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName((yyvsp[(1) - (4)].conststr)); (yyval.typnam)->typmods = list_make1(makeIntConst((yyvsp[(3) - (4)].ival), (yylsp[(3) - (4)]))); @@ -27974,8 +28236,8 @@ YYLTYPE yylloc; ;} break; - case 918: -#line 2020 "third_party/libpg_query/grammar/statements/select.y" + case 928: +#line 2042 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName((yyvsp[(1) - (1)].conststr)); /* char defaults to char(1), varchar to no limit */ @@ -27985,48 +28247,48 @@ YYLTYPE yylloc; ;} break; - case 919: -#line 2030 "third_party/libpg_query/grammar/statements/select.y" + case 929: +#line 2052 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; - case 920: -#line 2032 "third_party/libpg_query/grammar/statements/select.y" + case 930: +#line 2054 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; - case 921: -#line 2034 "third_party/libpg_query/grammar/statements/select.y" + case 931: +#line 2056 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "varchar"; ;} break; - case 922: -#line 2036 "third_party/libpg_query/grammar/statements/select.y" + case 932: +#line 2058 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(3) - (3)].boolean) ? "varchar": "bpchar"; ;} break; - case 923: -#line 2038 "third_party/libpg_query/grammar/statements/select.y" + case 933: +#line 2060 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(3) - (3)].boolean) ? "varchar": "bpchar"; ;} break; - case 924: -#line 2040 "third_party/libpg_query/grammar/statements/select.y" + case 934: +#line 2062 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; - case 925: -#line 2044 "third_party/libpg_query/grammar/statements/select.y" + case 935: +#line 2066 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 926: -#line 2045 "third_party/libpg_query/grammar/statements/select.y" + case 936: +#line 2067 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 927: -#line 2053 "third_party/libpg_query/grammar/statements/select.y" + case 937: +#line 2075 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(5) - (5)].boolean)) (yyval.typnam) = SystemTypeName("timestamptz"); @@ -28037,8 +28299,8 @@ YYLTYPE yylloc; ;} break; - case 928: -#line 2062 "third_party/libpg_query/grammar/statements/select.y" + case 938: +#line 2084 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].boolean)) (yyval.typnam) = SystemTypeName("timestamptz"); @@ -28048,8 +28310,8 @@ YYLTYPE yylloc; ;} break; - case 929: -#line 2070 "third_party/libpg_query/grammar/statements/select.y" + case 939: +#line 2092 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(5) - (5)].boolean)) (yyval.typnam) = SystemTypeName("timetz"); @@ -28060,8 +28322,8 @@ YYLTYPE yylloc; ;} break; - case 930: -#line 2079 "third_party/libpg_query/grammar/statements/select.y" + case 940: +#line 2101 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].boolean)) (yyval.typnam) = SystemTypeName("timetz"); @@ -28071,112 +28333,112 @@ YYLTYPE yylloc; ;} break; - case 931: -#line 2090 "third_party/libpg_query/grammar/statements/select.y" + case 941: +#line 2112 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("interval"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 932: -#line 2097 "third_party/libpg_query/grammar/statements/select.y" + case 942: +#line 2119 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 933: -#line 2098 "third_party/libpg_query/grammar/statements/select.y" + case 943: +#line 2120 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 934: -#line 2099 "third_party/libpg_query/grammar/statements/select.y" + case 944: +#line 2121 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 961: -#line 2143 "third_party/libpg_query/grammar/statements/select.y" + case 971: +#line 2165 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(YEAR), (yylsp[(1) - (1)]))); ;} break; - case 962: -#line 2145 "third_party/libpg_query/grammar/statements/select.y" + case 972: +#line 2167 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MONTH), (yylsp[(1) - (1)]))); ;} break; - case 963: -#line 2147 "third_party/libpg_query/grammar/statements/select.y" + case 973: +#line 2169 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY), (yylsp[(1) - (1)]))); ;} break; - case 964: -#line 2149 "third_party/libpg_query/grammar/statements/select.y" + case 974: +#line 2171 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR), (yylsp[(1) - (1)]))); ;} break; - case 965: -#line 2151 "third_party/libpg_query/grammar/statements/select.y" + case 975: +#line 2173 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), (yylsp[(1) - (1)]))); ;} break; - case 966: -#line 2153 "third_party/libpg_query/grammar/statements/select.y" + case 976: +#line 2175 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(SECOND), (yylsp[(1) - (1)]))); ;} break; - case 967: -#line 2155 "third_party/libpg_query/grammar/statements/select.y" + case 977: +#line 2177 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MILLISECOND), (yylsp[(1) - (1)]))); ;} break; - case 968: -#line 2157 "third_party/libpg_query/grammar/statements/select.y" + case 978: +#line 2179 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MICROSECOND), (yylsp[(1) - (1)]))); ;} break; - case 969: -#line 2159 "third_party/libpg_query/grammar/statements/select.y" + case 979: +#line 2181 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(WEEK), (yylsp[(1) - (1)]))); ;} break; - case 970: -#line 2161 "third_party/libpg_query/grammar/statements/select.y" + case 980: +#line 2183 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(QUARTER), (yylsp[(1) - (1)]))); ;} break; - case 971: -#line 2163 "third_party/libpg_query/grammar/statements/select.y" + case 981: +#line 2185 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DECADE), (yylsp[(1) - (1)]))); ;} break; - case 972: -#line 2165 "third_party/libpg_query/grammar/statements/select.y" + case 982: +#line 2187 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(CENTURY), (yylsp[(1) - (1)]))); ;} break; - case 973: -#line 2167 "third_party/libpg_query/grammar/statements/select.y" + case 983: +#line 2189 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MILLENNIUM), (yylsp[(1) - (1)]))); ;} break; - case 974: -#line 2169 "third_party/libpg_query/grammar/statements/select.y" + case 984: +#line 2191 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH), (yylsp[(1) - (3)]))); ;} break; - case 975: -#line 2174 "third_party/libpg_query/grammar/statements/select.y" + case 985: +#line 2196 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR), (yylsp[(1) - (3)]))); ;} break; - case 976: -#line 2179 "third_party/libpg_query/grammar/statements/select.y" + case 986: +#line 2201 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | @@ -28184,8 +28446,8 @@ YYLTYPE yylloc; ;} break; - case 977: -#line 2185 "third_party/libpg_query/grammar/statements/select.y" + case 987: +#line 2207 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | @@ -28194,16 +28456,16 @@ YYLTYPE yylloc; ;} break; - case 978: -#line 2192 "third_party/libpg_query/grammar/statements/select.y" + case 988: +#line 2214 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE), (yylsp[(1) - (3)]))); ;} break; - case 979: -#line 2197 "third_party/libpg_query/grammar/statements/select.y" + case 989: +#line 2219 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | @@ -28211,31 +28473,31 @@ YYLTYPE yylloc; ;} break; - case 980: -#line 2203 "third_party/libpg_query/grammar/statements/select.y" + case 990: +#line 2225 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND), (yylsp[(1) - (3)]))); ;} break; - case 981: -#line 2208 "third_party/libpg_query/grammar/statements/select.y" + case 991: +#line 2230 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 982: -#line 2239 "third_party/libpg_query/grammar/statements/select.y" + case 992: +#line 2261 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 983: -#line 2242 "third_party/libpg_query/grammar/statements/select.y" + case 993: +#line 2264 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeTypeCast((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].typnam), 0, (yylsp[(2) - (3)])); ;} break; - case 984: -#line 2244 "third_party/libpg_query/grammar/statements/select.y" + case 994: +#line 2266 "third_party/libpg_query/grammar/statements/select.y" { PGCollateClause *n = makeNode(PGCollateClause); n->arg = (yyvsp[(1) - (3)].node); @@ -28245,8 +28507,8 @@ YYLTYPE yylloc; ;} break; - case 985: -#line 2252 "third_party/libpg_query/grammar/statements/select.y" + case 995: +#line 2274 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("timezone"), list_make2((yyvsp[(5) - (5)].node), (yyvsp[(1) - (5)].node)), @@ -28254,139 +28516,139 @@ YYLTYPE yylloc; ;} break; - case 986: -#line 2267 "third_party/libpg_query/grammar/statements/select.y" + case 996: +#line 2289 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 987: -#line 2269 "third_party/libpg_query/grammar/statements/select.y" + case 997: +#line 2291 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 988: -#line 2271 "third_party/libpg_query/grammar/statements/select.y" + case 998: +#line 2293 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 989: -#line 2273 "third_party/libpg_query/grammar/statements/select.y" + case 999: +#line 2295 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "-", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 990: -#line 2275 "third_party/libpg_query/grammar/statements/select.y" + case 1000: +#line 2297 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "*", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 991: -#line 2277 "third_party/libpg_query/grammar/statements/select.y" + case 1001: +#line 2299 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "/", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 992: -#line 2279 "third_party/libpg_query/grammar/statements/select.y" + case 1002: +#line 2301 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "//", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 993: -#line 2281 "third_party/libpg_query/grammar/statements/select.y" + case 1003: +#line 2303 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "%", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 994: -#line 2283 "third_party/libpg_query/grammar/statements/select.y" + case 1004: +#line 2305 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "^", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 995: -#line 2285 "third_party/libpg_query/grammar/statements/select.y" + case 1005: +#line 2307 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "**", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 996: -#line 2287 "third_party/libpg_query/grammar/statements/select.y" + case 1006: +#line 2309 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 997: -#line 2289 "third_party/libpg_query/grammar/statements/select.y" + case 1007: +#line 2311 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, ">", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 998: -#line 2291 "third_party/libpg_query/grammar/statements/select.y" + case 1008: +#line 2313 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 999: -#line 2293 "third_party/libpg_query/grammar/statements/select.y" + case 1009: +#line 2315 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1000: -#line 2295 "third_party/libpg_query/grammar/statements/select.y" + case 1010: +#line 2317 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, ">=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1001: -#line 2297 "third_party/libpg_query/grammar/statements/select.y" + case 1011: +#line 2319 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<>", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1002: -#line 2300 "third_party/libpg_query/grammar/statements/select.y" + case 1012: +#line 2322 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(2) - (3)].list), (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1003: -#line 2302 "third_party/libpg_query/grammar/statements/select.y" + case 1013: +#line 2324 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(1) - (2)].list), NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1004: -#line 2304 "third_party/libpg_query/grammar/statements/select.y" + case 1014: +#line 2326 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(2) - (2)].list), (yyvsp[(1) - (2)].node), NULL, (yylsp[(2) - (2)])); ;} break; - case 1005: -#line 2307 "third_party/libpg_query/grammar/statements/select.y" + case 1015: +#line 2329 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeAndExpr((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1006: -#line 2309 "third_party/libpg_query/grammar/statements/select.y" + case 1016: +#line 2331 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeOrExpr((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1007: -#line 2311 "third_party/libpg_query/grammar/statements/select.y" + case 1017: +#line 2333 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNotExpr((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1008: -#line 2313 "third_party/libpg_query/grammar/statements/select.y" + case 1018: +#line 2335 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNotExpr((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1009: -#line 2315 "third_party/libpg_query/grammar/statements/select.y" + case 1019: +#line 2337 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_GLOB, "~~~", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1010: -#line 2320 "third_party/libpg_query/grammar/statements/select.y" + case 1020: +#line 2342 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_LIKE, "~~", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1011: -#line 2325 "third_party/libpg_query/grammar/statements/select.y" + case 1021: +#line 2347 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("like_escape"), list_make3((yyvsp[(1) - (5)].node), (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)), @@ -28395,16 +28657,16 @@ YYLTYPE yylloc; ;} break; - case 1012: -#line 2332 "third_party/libpg_query/grammar/statements/select.y" + case 1022: +#line 2354 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_LIKE, "!~~", (yyvsp[(1) - (4)].node), (yyvsp[(4) - (4)].node), (yylsp[(2) - (4)])); ;} break; - case 1013: -#line 2337 "third_party/libpg_query/grammar/statements/select.y" + case 1023: +#line 2359 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("not_like_escape"), list_make3((yyvsp[(1) - (6)].node), (yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -28413,16 +28675,16 @@ YYLTYPE yylloc; ;} break; - case 1014: -#line 2344 "third_party/libpg_query/grammar/statements/select.y" + case 1024: +#line 2366 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_ILIKE, "~~*", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1015: -#line 2349 "third_party/libpg_query/grammar/statements/select.y" + case 1025: +#line 2371 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("ilike_escape"), list_make3((yyvsp[(1) - (5)].node), (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)), @@ -28431,16 +28693,16 @@ YYLTYPE yylloc; ;} break; - case 1016: -#line 2356 "third_party/libpg_query/grammar/statements/select.y" + case 1026: +#line 2378 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_ILIKE, "!~~*", (yyvsp[(1) - (4)].node), (yyvsp[(4) - (4)].node), (yylsp[(2) - (4)])); ;} break; - case 1017: -#line 2361 "third_party/libpg_query/grammar/statements/select.y" + case 1027: +#line 2383 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("not_ilike_escape"), list_make3((yyvsp[(1) - (6)].node), (yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -28449,8 +28711,8 @@ YYLTYPE yylloc; ;} break; - case 1018: -#line 2369 "third_party/libpg_query/grammar/statements/select.y" + case 1028: +#line 2391 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(4) - (4)].node), makeNullAConst(-1)), @@ -28460,8 +28722,8 @@ YYLTYPE yylloc; ;} break; - case 1019: -#line 2377 "third_party/libpg_query/grammar/statements/select.y" + case 1029: +#line 2399 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -28471,8 +28733,8 @@ YYLTYPE yylloc; ;} break; - case 1020: -#line 2385 "third_party/libpg_query/grammar/statements/select.y" + case 1030: +#line 2407 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(5) - (5)].node), makeNullAConst(-1)), @@ -28482,8 +28744,8 @@ YYLTYPE yylloc; ;} break; - case 1021: -#line 2393 "third_party/libpg_query/grammar/statements/select.y" + case 1031: +#line 2415 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)), @@ -28493,8 +28755,8 @@ YYLTYPE yylloc; ;} break; - case 1022: -#line 2411 "third_party/libpg_query/grammar/statements/select.y" + case 1032: +#line 2433 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -28504,8 +28766,8 @@ YYLTYPE yylloc; ;} break; - case 1023: -#line 2419 "third_party/libpg_query/grammar/statements/select.y" + case 1033: +#line 2441 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (2)].node); @@ -28515,8 +28777,8 @@ YYLTYPE yylloc; ;} break; - case 1024: -#line 2427 "third_party/libpg_query/grammar/statements/select.y" + case 1034: +#line 2449 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -28526,8 +28788,8 @@ YYLTYPE yylloc; ;} break; - case 1025: -#line 2435 "third_party/libpg_query/grammar/statements/select.y" + case 1035: +#line 2457 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -28537,8 +28799,8 @@ YYLTYPE yylloc; ;} break; - case 1026: -#line 2443 "third_party/libpg_query/grammar/statements/select.y" + case 1036: +#line 2465 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (2)].node); @@ -28548,8 +28810,8 @@ YYLTYPE yylloc; ;} break; - case 1027: -#line 2451 "third_party/libpg_query/grammar/statements/select.y" + case 1037: +#line 2473 "third_party/libpg_query/grammar/statements/select.y" { PGLambdaFunction *n = makeNode(PGLambdaFunction); n->lhs = (yyvsp[(2) - (4)].list); @@ -28559,8 +28821,8 @@ YYLTYPE yylloc; ;} break; - case 1028: -#line 2459 "third_party/libpg_query/grammar/statements/select.y" + case 1038: +#line 2481 "third_party/libpg_query/grammar/statements/select.y" { PGSingleArrowFunction *n = makeNode(PGSingleArrowFunction); n->lhs = (yyvsp[(1) - (3)].node); @@ -28570,15 +28832,15 @@ YYLTYPE yylloc; ;} break; - case 1029: -#line 2467 "third_party/libpg_query/grammar/statements/select.y" + case 1039: +#line 2489 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "->>", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1030: -#line 2471 "third_party/libpg_query/grammar/statements/select.y" + case 1040: +#line 2493 "third_party/libpg_query/grammar/statements/select.y" { if (list_length((yyvsp[(1) - (3)].list)) != 2) ereport(ERROR, @@ -28596,8 +28858,8 @@ YYLTYPE yylloc; ;} break; - case 1031: -#line 2487 "third_party/libpg_query/grammar/statements/select.y" + case 1041: +#line 2509 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -28607,8 +28869,8 @@ YYLTYPE yylloc; ;} break; - case 1032: -#line 2495 "third_party/libpg_query/grammar/statements/select.y" + case 1042: +#line 2517 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -28618,8 +28880,8 @@ YYLTYPE yylloc; ;} break; - case 1033: -#line 2503 "third_party/libpg_query/grammar/statements/select.y" + case 1043: +#line 2525 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -28629,8 +28891,8 @@ YYLTYPE yylloc; ;} break; - case 1034: -#line 2511 "third_party/libpg_query/grammar/statements/select.y" + case 1044: +#line 2533 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -28640,8 +28902,8 @@ YYLTYPE yylloc; ;} break; - case 1035: -#line 2519 "third_party/libpg_query/grammar/statements/select.y" + case 1045: +#line 2541 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -28651,8 +28913,8 @@ YYLTYPE yylloc; ;} break; - case 1036: -#line 2527 "third_party/libpg_query/grammar/statements/select.y" + case 1046: +#line 2549 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -28662,36 +28924,36 @@ YYLTYPE yylloc; ;} break; - case 1037: -#line 2535 "third_party/libpg_query/grammar/statements/select.y" + case 1047: +#line 2557 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_DISTINCT, "=", (yyvsp[(1) - (5)].node), (yyvsp[(5) - (5)].node), (yylsp[(2) - (5)])); ;} break; - case 1038: -#line 2539 "third_party/libpg_query/grammar/statements/select.y" + case 1048: +#line 2561 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_DISTINCT, "=", (yyvsp[(1) - (6)].node), (yyvsp[(6) - (6)].node), (yylsp[(2) - (6)])); ;} break; - case 1039: -#line 2543 "third_party/libpg_query/grammar/statements/select.y" + case 1049: +#line 2565 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OF, "=", (yyvsp[(1) - (6)].node), (PGNode *) (yyvsp[(5) - (6)].list), (yylsp[(2) - (6)])); ;} break; - case 1040: -#line 2547 "third_party/libpg_query/grammar/statements/select.y" + case 1050: +#line 2569 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OF, "<>", (yyvsp[(1) - (7)].node), (PGNode *) (yyvsp[(6) - (7)].list), (yylsp[(2) - (7)])); ;} break; - case 1041: -#line 2551 "third_party/libpg_query/grammar/statements/select.y" + case 1051: +#line 2573 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_BETWEEN, "BETWEEN", @@ -28701,8 +28963,8 @@ YYLTYPE yylloc; ;} break; - case 1042: -#line 2559 "third_party/libpg_query/grammar/statements/select.y" + case 1052: +#line 2581 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_BETWEEN, "NOT BETWEEN", @@ -28712,8 +28974,8 @@ YYLTYPE yylloc; ;} break; - case 1043: -#line 2567 "third_party/libpg_query/grammar/statements/select.y" + case 1053: +#line 2589 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_BETWEEN_SYM, "BETWEEN SYMMETRIC", @@ -28723,8 +28985,8 @@ YYLTYPE yylloc; ;} break; - case 1044: -#line 2575 "third_party/libpg_query/grammar/statements/select.y" + case 1054: +#line 2597 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_BETWEEN_SYM, "NOT BETWEEN SYMMETRIC", @@ -28734,8 +28996,8 @@ YYLTYPE yylloc; ;} break; - case 1045: -#line 2583 "third_party/libpg_query/grammar/statements/select.y" + case 1055: +#line 2605 "third_party/libpg_query/grammar/statements/select.y" { /* in_expr returns a PGSubLink or a list of a_exprs */ if (IsA((yyvsp[(3) - (3)].node), PGSubLink)) @@ -28757,8 +29019,8 @@ YYLTYPE yylloc; ;} break; - case 1046: -#line 2603 "third_party/libpg_query/grammar/statements/select.y" + case 1056: +#line 2625 "third_party/libpg_query/grammar/statements/select.y" { /* in_expr returns a PGSubLink or a list of a_exprs */ if (IsA((yyvsp[(4) - (4)].node), PGSubLink)) @@ -28782,8 +29044,8 @@ YYLTYPE yylloc; ;} break; - case 1047: -#line 2625 "third_party/libpg_query/grammar/statements/select.y" + case 1057: +#line 2647 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = (yyvsp[(3) - (4)].subquerytype); @@ -28796,8 +29058,8 @@ YYLTYPE yylloc; ;} break; - case 1048: -#line 2636 "third_party/libpg_query/grammar/statements/select.y" + case 1058: +#line 2658 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(3) - (6)].subquerytype) == PG_ANY_SUBLINK) (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP_ANY, (yyvsp[(2) - (6)].list), (yyvsp[(1) - (6)].node), (yyvsp[(5) - (6)].node), (yylsp[(2) - (6)])); @@ -28806,8 +29068,8 @@ YYLTYPE yylloc; ;} break; - case 1049: -#line 2643 "third_party/libpg_query/grammar/statements/select.y" + case 1059: +#line 2665 "third_party/libpg_query/grammar/statements/select.y" { /* * The SQL spec only allows DEFAULT in "contextually typed @@ -28823,8 +29085,8 @@ YYLTYPE yylloc; ;} break; - case 1050: -#line 2657 "third_party/libpg_query/grammar/statements/select.y" + case 1060: +#line 2679 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); star->expr = (yyvsp[(3) - (4)].node); @@ -28834,16 +29096,16 @@ YYLTYPE yylloc; ;} break; - case 1051: -#line 2665 "third_party/libpg_query/grammar/statements/select.y" + case 1061: +#line 2687 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("unpack"), list_make1((yyvsp[(3) - (4)].node)), (yylsp[(1) - (4)])); (yyval.node) = (PGNode *) n; ;} break; - case 1052: -#line 2670 "third_party/libpg_query/grammar/statements/select.y" + case 1062: +#line 2692 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); star->expr = (yyvsp[(4) - (5)].node); @@ -28855,8 +29117,8 @@ YYLTYPE yylloc; ;} break; - case 1053: -#line 2680 "third_party/libpg_query/grammar/statements/select.y" + case 1063: +#line 2702 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); star->except_list = (yyvsp[(2) - (4)].list); @@ -28867,8 +29129,8 @@ YYLTYPE yylloc; ;} break; - case 1054: -#line 2689 "third_party/libpg_query/grammar/statements/select.y" + case 1064: +#line 2711 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); star->relation = (yyvsp[(1) - (6)].str); @@ -28880,141 +29142,141 @@ YYLTYPE yylloc; ;} break; - case 1055: -#line 2710 "third_party/libpg_query/grammar/statements/select.y" + case 1065: +#line 2732 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1056: -#line 2712 "third_party/libpg_query/grammar/statements/select.y" + case 1066: +#line 2734 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeTypeCast((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].typnam), 0, (yylsp[(2) - (3)])); ;} break; - case 1057: -#line 2714 "third_party/libpg_query/grammar/statements/select.y" + case 1067: +#line 2736 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1058: -#line 2716 "third_party/libpg_query/grammar/statements/select.y" + case 1068: +#line 2738 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1059: -#line 2718 "third_party/libpg_query/grammar/statements/select.y" + case 1069: +#line 2740 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1060: -#line 2720 "third_party/libpg_query/grammar/statements/select.y" + case 1070: +#line 2742 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "-", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1061: -#line 2722 "third_party/libpg_query/grammar/statements/select.y" + case 1071: +#line 2744 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "*", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1062: -#line 2724 "third_party/libpg_query/grammar/statements/select.y" + case 1072: +#line 2746 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "/", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1063: -#line 2726 "third_party/libpg_query/grammar/statements/select.y" + case 1073: +#line 2748 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "//", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1064: -#line 2728 "third_party/libpg_query/grammar/statements/select.y" + case 1074: +#line 2750 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "%", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1065: -#line 2730 "third_party/libpg_query/grammar/statements/select.y" + case 1075: +#line 2752 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "^", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1066: -#line 2732 "third_party/libpg_query/grammar/statements/select.y" + case 1076: +#line 2754 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "**", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1067: -#line 2734 "third_party/libpg_query/grammar/statements/select.y" + case 1077: +#line 2756 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1068: -#line 2736 "third_party/libpg_query/grammar/statements/select.y" + case 1078: +#line 2758 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, ">", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1069: -#line 2738 "third_party/libpg_query/grammar/statements/select.y" + case 1079: +#line 2760 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1070: -#line 2740 "third_party/libpg_query/grammar/statements/select.y" + case 1080: +#line 2762 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1071: -#line 2742 "third_party/libpg_query/grammar/statements/select.y" + case 1081: +#line 2764 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, ">=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1072: -#line 2744 "third_party/libpg_query/grammar/statements/select.y" + case 1082: +#line 2766 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<>", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1073: -#line 2746 "third_party/libpg_query/grammar/statements/select.y" + case 1083: +#line 2768 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(2) - (3)].list), (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1074: -#line 2748 "third_party/libpg_query/grammar/statements/select.y" + case 1084: +#line 2770 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(1) - (2)].list), NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1075: -#line 2750 "third_party/libpg_query/grammar/statements/select.y" + case 1085: +#line 2772 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(2) - (2)].list), (yyvsp[(1) - (2)].node), NULL, (yylsp[(2) - (2)])); ;} break; - - case 1076: -#line 2752 "third_party/libpg_query/grammar/statements/select.y" + + case 1086: +#line 2774 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_DISTINCT, "=", (yyvsp[(1) - (5)].node), (yyvsp[(5) - (5)].node), (yylsp[(2) - (5)])); ;} break; - case 1077: -#line 2756 "third_party/libpg_query/grammar/statements/select.y" + case 1087: +#line 2778 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_DISTINCT, "=", (yyvsp[(1) - (6)].node), (yyvsp[(6) - (6)].node), (yylsp[(2) - (6)])); ;} break; - case 1078: -#line 2760 "third_party/libpg_query/grammar/statements/select.y" + case 1088: +#line 2782 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OF, "=", (yyvsp[(1) - (6)].node), (PGNode *) (yyvsp[(5) - (6)].list), (yylsp[(2) - (6)])); ;} break; - case 1079: -#line 2764 "third_party/libpg_query/grammar/statements/select.y" + case 1089: +#line 2786 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OF, "<>", (yyvsp[(1) - (7)].node), (PGNode *) (yyvsp[(6) - (7)].list), (yylsp[(2) - (7)])); ;} break; - case 1081: -#line 2779 "third_party/libpg_query/grammar/statements/select.y" + case 1091: +#line 2801 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].list)) { @@ -29028,18 +29290,18 @@ YYLTYPE yylloc; ;} break; - case 1082: -#line 2792 "third_party/libpg_query/grammar/statements/select.y" + case 1092: +#line 2814 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1083: -#line 2793 "third_party/libpg_query/grammar/statements/select.y" + case 1093: +#line 2815 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1084: -#line 2795 "third_party/libpg_query/grammar/statements/select.y" + case 1094: +#line 2817 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = PG_EXPR_SUBLINK; @@ -29052,8 +29314,8 @@ YYLTYPE yylloc; ;} break; - case 1085: -#line 2806 "third_party/libpg_query/grammar/statements/select.y" + case 1095: +#line 2828 "third_party/libpg_query/grammar/statements/select.y" { /* * Because the select_with_parens nonterminal is designed @@ -29079,8 +29341,8 @@ YYLTYPE yylloc; ;} break; - case 1086: -#line 2830 "third_party/libpg_query/grammar/statements/select.y" + case 1096: +#line 2852 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = PG_EXISTS_SUBLINK; @@ -29093,8 +29355,8 @@ YYLTYPE yylloc; ;} break; - case 1087: -#line 2841 "third_party/libpg_query/grammar/statements/select.y" + case 1097: +#line 2863 "third_party/libpg_query/grammar/statements/select.y" { PGGroupingFunc *g = makeNode(PGGroupingFunc); g->args = (yyvsp[(3) - (4)].list); @@ -29103,37 +29365,37 @@ YYLTYPE yylloc; ;} break; - case 1088: -#line 2851 "third_party/libpg_query/grammar/statements/select.y" + case 1098: +#line 2873 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (3)].node); ;} break; - case 1089: -#line 2855 "third_party/libpg_query/grammar/statements/select.y" + case 1099: +#line 2877 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1090: -#line 2858 "third_party/libpg_query/grammar/statements/select.y" + case 1100: +#line 2880 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("row"), (yyvsp[(1) - (1)].list), (yylsp[(1) - (1)])); (yyval.node) = (PGNode *) n; ;} break; - case 1091: -#line 2866 "third_party/libpg_query/grammar/statements/select.y" + case 1101: +#line 2888 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeParamRef(0, (yylsp[(1) - (1)])); ;} break; - case 1092: -#line 2870 "third_party/libpg_query/grammar/statements/select.y" + case 1102: +#line 2892 "third_party/libpg_query/grammar/statements/select.y" { PGParamRef *p = makeNode(PGParamRef); p->number = (yyvsp[(1) - (1)].ival); @@ -29142,15 +29404,15 @@ YYLTYPE yylloc; ;} break; - case 1093: -#line 2877 "third_party/libpg_query/grammar/statements/select.y" + case 1103: +#line 2899 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNamedParamRef((yyvsp[(2) - (2)].str), (yylsp[(1) - (2)])); ;} break; - case 1101: -#line 2891 "third_party/libpg_query/grammar/statements/select.y" + case 1111: +#line 2913 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = PG_ARRAY_SUBLINK; @@ -29163,8 +29425,8 @@ YYLTYPE yylloc; ;} break; - case 1102: -#line 2901 "third_party/libpg_query/grammar/statements/select.y" + case 1112: +#line 2923 "third_party/libpg_query/grammar/statements/select.y" { PGList *func_name = list_make1(makeString("construct_array")); PGFuncCall *n = makeFuncCall(func_name, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); @@ -29172,8 +29434,8 @@ YYLTYPE yylloc; ;} break; - case 1103: -#line 2907 "third_party/libpg_query/grammar/statements/select.y" + case 1113: +#line 2929 "third_party/libpg_query/grammar/statements/select.y" { PGPositionalReference *n = makeNode(PGPositionalReference); n->position = (yyvsp[(2) - (2)].ival); @@ -29182,24 +29444,24 @@ YYLTYPE yylloc; ;} break; - case 1104: -#line 2915 "third_party/libpg_query/grammar/statements/select.y" + case 1114: +#line 2937 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("list_value"), (yyvsp[(2) - (3)].list), (yylsp[(2) - (3)])); (yyval.node) = (PGNode *) n; ;} break; - case 1105: -#line 2922 "third_party/libpg_query/grammar/statements/select.y" + case 1115: +#line 2944 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *f = makeFuncCall(SystemFuncName("struct_pack"), (yyvsp[(2) - (3)].list), (yylsp[(2) - (3)])); (yyval.node) = (PGNode *) f; ;} break; - case 1106: -#line 2929 "third_party/libpg_query/grammar/statements/select.y" + case 1116: +#line 2951 "third_party/libpg_query/grammar/statements/select.y" { PGList *key_list = NULL; PGList *value_list = NULL; @@ -29218,15 +29480,15 @@ YYLTYPE yylloc; ;} break; - case 1107: -#line 2949 "third_party/libpg_query/grammar/statements/select.y" + case 1117: +#line 2971 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall((yyvsp[(1) - (3)].list), NIL, (yylsp[(1) - (3)])); ;} break; - case 1108: -#line 2953 "third_party/libpg_query/grammar/statements/select.y" + case 1118: +#line 2975 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (5)].list), NIL, (yylsp[(1) - (5)])); n->agg_order = (yyvsp[(3) - (5)].list); @@ -29235,8 +29497,8 @@ YYLTYPE yylloc; ;} break; - case 1109: -#line 2960 "third_party/libpg_query/grammar/statements/select.y" + case 1119: +#line 2982 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (6)].list), (yyvsp[(3) - (6)].list), (yylsp[(1) - (6)])); n->agg_order = (yyvsp[(4) - (6)].list); @@ -29245,8 +29507,8 @@ YYLTYPE yylloc; ;} break; - case 1110: -#line 2967 "third_party/libpg_query/grammar/statements/select.y" + case 1120: +#line 2989 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (7)].list), list_make1((yyvsp[(4) - (7)].node)), (yylsp[(1) - (7)])); n->func_variadic = true; @@ -29256,8 +29518,8 @@ YYLTYPE yylloc; ;} break; - case 1111: -#line 2975 "third_party/libpg_query/grammar/statements/select.y" + case 1121: +#line 2997 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (9)].list), lappend((yyvsp[(3) - (9)].list), (yyvsp[(6) - (9)].node)), (yylsp[(1) - (9)])); n->func_variadic = true; @@ -29267,8 +29529,8 @@ YYLTYPE yylloc; ;} break; - case 1112: -#line 2983 "third_party/libpg_query/grammar/statements/select.y" + case 1122: +#line 3005 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (7)].list), (yyvsp[(4) - (7)].list), (yylsp[(1) - (7)])); n->agg_order = (yyvsp[(5) - (7)].list); @@ -29281,8 +29543,8 @@ YYLTYPE yylloc; ;} break; - case 1113: -#line 2994 "third_party/libpg_query/grammar/statements/select.y" + case 1123: +#line 3016 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (7)].list), (yyvsp[(4) - (7)].list), (yylsp[(1) - (7)])); n->agg_order = (yyvsp[(5) - (7)].list); @@ -29292,8 +29554,8 @@ YYLTYPE yylloc; ;} break; - case 1114: -#line 3014 "third_party/libpg_query/grammar/statements/select.y" + case 1124: +#line 3036 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = (PGFuncCall *) (yyvsp[(1) - (5)].node); /* @@ -29331,23 +29593,23 @@ YYLTYPE yylloc; ;} break; - case 1115: -#line 3050 "third_party/libpg_query/grammar/statements/select.y" + case 1125: +#line 3072 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1116: -#line 3060 "third_party/libpg_query/grammar/statements/select.y" + case 1126: +#line 3082 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1117: -#line 3061 "third_party/libpg_query/grammar/statements/select.y" + case 1127: +#line 3083 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1118: -#line 3069 "third_party/libpg_query/grammar/statements/select.y" + case 1128: +#line 3091 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("pg_collation_for"), list_make1((yyvsp[(4) - (5)].node)), @@ -29355,25 +29617,25 @@ YYLTYPE yylloc; ;} break; - case 1119: -#line 3075 "third_party/libpg_query/grammar/statements/select.y" + case 1129: +#line 3097 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeTypeCast((yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].typnam), 0, (yylsp[(1) - (6)])); ;} break; - case 1120: -#line 3077 "third_party/libpg_query/grammar/statements/select.y" + case 1130: +#line 3099 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeTypeCast((yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].typnam), 1, (yylsp[(1) - (6)])); ;} break; - case 1121: -#line 3079 "third_party/libpg_query/grammar/statements/select.y" + case 1131: +#line 3101 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("date_part"), (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 1122: -#line 3083 "third_party/libpg_query/grammar/statements/select.y" + case 1132: +#line 3105 "third_party/libpg_query/grammar/statements/select.y" { /* overlay(A PLACING B FROM C FOR D) is converted to * overlay(A, B, C, D) @@ -29384,16 +29646,16 @@ YYLTYPE yylloc; ;} break; - case 1123: -#line 3092 "third_party/libpg_query/grammar/statements/select.y" + case 1133: +#line 3114 "third_party/libpg_query/grammar/statements/select.y" { /* position(A in B) is converted to position_inverse(A, B) */ (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("__internal_position_operator"), (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 1124: -#line 3097 "third_party/libpg_query/grammar/statements/select.y" + case 1134: +#line 3119 "third_party/libpg_query/grammar/statements/select.y" { /* substring(A from B for C) is converted to * substring(A, B, C) - thomas 2000-11-28 @@ -29402,8 +29664,8 @@ YYLTYPE yylloc; ;} break; - case 1125: -#line 3104 "third_party/libpg_query/grammar/statements/select.y" + case 1135: +#line 3126 "third_party/libpg_query/grammar/statements/select.y" { /* TREAT(expr AS target) converts expr of a particular type to target, * which is defined to be a subtype of the original expression. @@ -29420,8 +29682,8 @@ YYLTYPE yylloc; ;} break; - case 1126: -#line 3119 "third_party/libpg_query/grammar/statements/select.y" + case 1136: +#line 3141 "third_party/libpg_query/grammar/statements/select.y" { /* various trim expressions are defined in SQL * - thomas 1997-07-19 @@ -29430,36 +29692,36 @@ YYLTYPE yylloc; ;} break; - case 1127: -#line 3126 "third_party/libpg_query/grammar/statements/select.y" + case 1137: +#line 3148 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("ltrim"), (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); ;} break; - case 1128: -#line 3130 "third_party/libpg_query/grammar/statements/select.y" + case 1138: +#line 3152 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("rtrim"), (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); ;} break; - case 1129: -#line 3134 "third_party/libpg_query/grammar/statements/select.y" + case 1139: +#line 3156 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("trim"), (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 1130: -#line 3138 "third_party/libpg_query/grammar/statements/select.y" + case 1140: +#line 3160 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NULLIF, "=", (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node), (yylsp[(1) - (6)])); ;} break; - case 1131: -#line 3142 "third_party/libpg_query/grammar/statements/select.y" + case 1141: +#line 3164 "third_party/libpg_query/grammar/statements/select.y" { PGCoalesceExpr *c = makeNode(PGCoalesceExpr); c->args = (yyvsp[(3) - (4)].list); @@ -29468,8 +29730,8 @@ YYLTYPE yylloc; ;} break; - case 1132: -#line 3152 "third_party/libpg_query/grammar/statements/select.y" + case 1142: +#line 3174 "third_party/libpg_query/grammar/statements/select.y" { PGLambdaFunction *lambda = makeNode(PGLambdaFunction); lambda->lhs = (yyvsp[(4) - (7)].list); @@ -29480,81 +29742,119 @@ YYLTYPE yylloc; ;} break; - case 1133: -#line 3161 "third_party/libpg_query/grammar/statements/select.y" + case 1143: +#line 3183 "third_party/libpg_query/grammar/statements/select.y" { - PGLambdaFunction *lambda = makeNode(PGLambdaFunction); + /* Construct first apply */ + PGNamedArgExpr *filter_expr = makeNode(PGNamedArgExpr); + filter_expr->name = pstrdup("filter"); + filter_expr->arg = (PGExpr *) (yyvsp[(8) - (9)].node); + filter_expr->argnumber = -1; + filter_expr->location = (yylsp[(8) - (9)]); + + PGNamedArgExpr *result_expr = makeNode(PGNamedArgExpr); + result_expr->name = pstrdup("result"); + result_expr->arg = (PGExpr *) (yyvsp[(2) - (9)].node); + result_expr->argnumber = -1; + result_expr->location = (yylsp[(2) - (9)]); + + PGFuncCall *struct_pack = makeFuncCall(SystemFuncName("struct_pack"), list_make2(filter_expr, result_expr), (yylsp[(1) - (9)])); + + PGLambdaFunction *lambda_apply_1 = makeNode(PGLambdaFunction); + lambda_apply_1->lhs = (yyvsp[(4) - (9)].list); + lambda_apply_1->rhs = (PGNode *)struct_pack; + lambda_apply_1->location = (yylsp[(1) - (9)]); + + PGFuncCall *apply_func_1 = makeFuncCall(SystemFuncName("list_apply"), list_make2((yyvsp[(6) - (9)].node), lambda_apply_1), (yylsp[(1) - (9)])); + + /* Construct filter */ + PGNode *elem_column_ref_filter = makeColumnRef(pstrdup("elem"), NIL, (yylsp[(1) - (9)]), yyscanner); + PGNode *filter_column_name = makeStringConst("filter", (yylsp[(1) - (9)])); + PGFuncCall *filter_extract = makeFuncCall(SystemFuncName("struct_extract"), list_make2(elem_column_ref_filter, filter_column_name), (yylsp[(1) - (9)])); PGLambdaFunction *lambda = makeNode(PGLambdaFunction); lambda->lhs = (yyvsp[(4) - (9)].list); lambda->rhs = (yyvsp[(2) - (9)].node); lambda->location = (yylsp[(1) - (9)]); PGLambdaFunction *lambda_filter = makeNode(PGLambdaFunction); - lambda_filter->lhs = (yyvsp[(4) - (9)].list); - lambda_filter->rhs = (yyvsp[(8) - (9)].node); - lambda_filter->location = (yylsp[(8) - (9)]); - PGFuncCall *filter = makeFuncCall(SystemFuncName("list_filter"), list_make2((yyvsp[(6) - (9)].node), lambda_filter), (yylsp[(1) - (9)])); - PGFuncCall *n = makeFuncCall(SystemFuncName("list_apply"), list_make2(filter, lambda), (yylsp[(1) - (9)])); - (yyval.node) = (PGNode *) n; + lambda_filter->lhs = list_make1(makeString("elem")); + lambda_filter->rhs = (PGNode *) filter_extract; + lambda_filter->location = (yylsp[(1) - (9)]); + + PGFuncCall *filter_func = makeFuncCall(SystemFuncName("list_filter"), list_make2(apply_func_1, lambda_filter), (yylsp[(1) - (9)])); + + /* Construct second apply */ + PGNode *elem_column_ref_result = makeColumnRef(pstrdup("elem"), NIL, (yylsp[(1) - (9)]), yyscanner); + PGNode *result_column_name = makeStringConst("result", (yylsp[(1) - (9)])); + PGFuncCall *result_extract = makeFuncCall(SystemFuncName("struct_extract"), list_make2(elem_column_ref_filter, result_column_name), (yylsp[(1) - (9)])); + + PGLambdaFunction *lambda_apply_2 = makeNode(PGLambdaFunction); + lambda_apply_2->lhs = list_make1(makeString("elem")); + lambda_apply_2->rhs = (PGNode *) result_extract; + lambda_apply_2->location = (yylsp[(1) - (9)]); + + PGFuncCall *apply_func_2 = makeFuncCall(SystemFuncName("list_apply"), list_make2(filter_func, lambda_apply_2), (yylsp[(1) - (9)])); + + (yyval.node) = (PGNode *) apply_func_2; ;} break; - case 1134: -#line 3182 "third_party/libpg_query/grammar/statements/select.y" + case 1144: +#line 3242 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(4) - (5)].list); ;} break; - case 1135: -#line 3183 "third_party/libpg_query/grammar/statements/select.y" + case 1145: +#line 3243 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1136: -#line 3187 "third_party/libpg_query/grammar/statements/select.y" + case 1146: +#line 3247 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(4) - (5)].node); ;} break; - case 1137: -#line 3188 "third_party/libpg_query/grammar/statements/select.y" + case 1147: +#line 3248 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(3) - (4)].node); ;} break; - case 1138: -#line 3189 "third_party/libpg_query/grammar/statements/select.y" + case 1148: +#line 3249 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1139: -#line 3193 "third_party/libpg_query/grammar/statements/select.y" + case 1149: +#line 3253 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 1140: -#line 3194 "third_party/libpg_query/grammar/statements/select.y" + case 1150: +#line 3254 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 1141: -#line 3201 "third_party/libpg_query/grammar/statements/select.y" + case 1151: +#line 3261 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1142: -#line 3202 "third_party/libpg_query/grammar/statements/select.y" + case 1152: +#line 3262 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1143: -#line 3206 "third_party/libpg_query/grammar/statements/select.y" + case 1153: +#line 3266 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].windef)); ;} break; - case 1144: -#line 3208 "third_party/libpg_query/grammar/statements/select.y" + case 1154: +#line 3268 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].windef)); ;} break; - case 1145: -#line 3213 "third_party/libpg_query/grammar/statements/select.y" + case 1155: +#line 3273 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(3) - (3)].windef); n->name = (yyvsp[(1) - (3)].str); @@ -29562,13 +29862,13 @@ YYLTYPE yylloc; ;} break; - case 1146: -#line 3221 "third_party/libpg_query/grammar/statements/select.y" + case 1156: +#line 3281 "third_party/libpg_query/grammar/statements/select.y" { (yyval.windef) = (yyvsp[(2) - (2)].windef); ;} break; - case 1147: -#line 3223 "third_party/libpg_query/grammar/statements/select.y" + case 1157: +#line 3283 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); n->name = (yyvsp[(2) - (2)].str); @@ -29583,13 +29883,13 @@ YYLTYPE yylloc; ;} break; - case 1148: -#line 3236 "third_party/libpg_query/grammar/statements/select.y" + case 1158: +#line 3296 "third_party/libpg_query/grammar/statements/select.y" { (yyval.windef) = NULL; ;} break; - case 1149: -#line 3241 "third_party/libpg_query/grammar/statements/select.y" + case 1159: +#line 3301 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); n->name = NULL; @@ -29605,28 +29905,28 @@ YYLTYPE yylloc; ;} break; - case 1150: -#line 3266 "third_party/libpg_query/grammar/statements/select.y" + case 1160: +#line 3326 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1151: -#line 3267 "third_party/libpg_query/grammar/statements/select.y" + case 1161: +#line 3327 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = NULL; ;} break; - case 1152: -#line 3270 "third_party/libpg_query/grammar/statements/select.y" + case 1162: +#line 3330 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 1153: -#line 3271 "third_party/libpg_query/grammar/statements/select.y" + case 1163: +#line 3331 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1154: -#line 3280 "third_party/libpg_query/grammar/statements/select.y" + case 1164: +#line 3340 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(2) - (3)].windef); @@ -29636,8 +29936,8 @@ YYLTYPE yylloc; ;} break; - case 1155: -#line 3288 "third_party/libpg_query/grammar/statements/select.y" + case 1165: +#line 3348 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(2) - (3)].windef); @@ -29647,8 +29947,8 @@ YYLTYPE yylloc; ;} break; - case 1156: -#line 3296 "third_party/libpg_query/grammar/statements/select.y" + case 1166: +#line 3356 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(2) - (3)].windef); @@ -29658,8 +29958,8 @@ YYLTYPE yylloc; ;} break; - case 1157: -#line 3304 "third_party/libpg_query/grammar/statements/select.y" + case 1167: +#line 3364 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -29670,8 +29970,8 @@ YYLTYPE yylloc; ;} break; - case 1158: -#line 3315 "third_party/libpg_query/grammar/statements/select.y" + case 1168: +#line 3375 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(1) - (1)].windef); @@ -29691,8 +29991,8 @@ YYLTYPE yylloc; ;} break; - case 1159: -#line 3333 "third_party/libpg_query/grammar/statements/select.y" + case 1169: +#line 3393 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n1 = (yyvsp[(2) - (4)].windef); PGWindowDef *n2 = (yyvsp[(4) - (4)].windef); @@ -29732,8 +30032,8 @@ YYLTYPE yylloc; ;} break; - case 1160: -#line 3379 "third_party/libpg_query/grammar/statements/select.y" + case 1170: +#line 3439 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -29744,8 +30044,8 @@ YYLTYPE yylloc; ;} break; - case 1161: -#line 3388 "third_party/libpg_query/grammar/statements/select.y" + case 1171: +#line 3448 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -29756,8 +30056,8 @@ YYLTYPE yylloc; ;} break; - case 1162: -#line 3397 "third_party/libpg_query/grammar/statements/select.y" + case 1172: +#line 3457 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -29768,8 +30068,8 @@ YYLTYPE yylloc; ;} break; - case 1163: -#line 3406 "third_party/libpg_query/grammar/statements/select.y" + case 1173: +#line 3466 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -29780,8 +30080,8 @@ YYLTYPE yylloc; ;} break; - case 1164: -#line 3415 "third_party/libpg_query/grammar/statements/select.y" + case 1174: +#line 3475 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -29792,53 +30092,53 @@ YYLTYPE yylloc; ;} break; - case 1165: -#line 3426 "third_party/libpg_query/grammar/statements/select.y" + case 1175: +#line 3486 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_CURRENT_ROW; ;} break; - case 1166: -#line 3427 "third_party/libpg_query/grammar/statements/select.y" + case 1176: +#line 3487 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_GROUP; ;} break; - case 1167: -#line 3428 "third_party/libpg_query/grammar/statements/select.y" + case 1177: +#line 3488 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_TIES; ;} break; - case 1168: -#line 3429 "third_party/libpg_query/grammar/statements/select.y" + case 1178: +#line 3489 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 1169: -#line 3430 "third_party/libpg_query/grammar/statements/select.y" + case 1179: +#line 3490 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 1170: -#line 3444 "third_party/libpg_query/grammar/statements/select.y" + case 1180: +#line 3504 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1171: -#line 3445 "third_party/libpg_query/grammar/statements/select.y" + case 1181: +#line 3505 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1172: -#line 3448 "third_party/libpg_query/grammar/statements/select.y" + case 1182: +#line 3508 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list);;} break; - case 1173: -#line 3449 "third_party/libpg_query/grammar/statements/select.y" + case 1183: +#line 3509 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(2) - (5)].list), (yyvsp[(4) - (5)].node)); ;} break; - case 1174: -#line 3453 "third_party/libpg_query/grammar/statements/select.y" + case 1184: +#line 3513 "third_party/libpg_query/grammar/statements/select.y" { PGNamedArgExpr *na = makeNode(PGNamedArgExpr); na->name = (yyvsp[(1) - (3)].str); @@ -29849,321 +30149,321 @@ YYLTYPE yylloc; ;} break; - case 1175: -#line 3463 "third_party/libpg_query/grammar/statements/select.y" + case 1185: +#line 3523 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1176: -#line 3464 "third_party/libpg_query/grammar/statements/select.y" + case 1186: +#line 3524 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1177: -#line 3468 "third_party/libpg_query/grammar/statements/select.y" + case 1187: +#line 3528 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1178: -#line 3469 "third_party/libpg_query/grammar/statements/select.y" + case 1188: +#line 3529 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1179: -#line 3474 "third_party/libpg_query/grammar/statements/select.y" + case 1189: +#line 3534 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1180: -#line 3480 "third_party/libpg_query/grammar/statements/select.y" + case 1190: +#line 3540 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 1181: -#line 3481 "third_party/libpg_query/grammar/statements/select.y" + case 1191: +#line 3541 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 1182: -#line 3486 "third_party/libpg_query/grammar/statements/select.y" + case 1192: +#line 3546 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1183: -#line 3487 "third_party/libpg_query/grammar/statements/select.y" + case 1193: +#line 3547 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1184: -#line 3492 "third_party/libpg_query/grammar/statements/select.y" + case 1194: +#line 3552 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1185: -#line 3493 "third_party/libpg_query/grammar/statements/select.y" + case 1195: +#line 3553 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1186: -#line 3496 "third_party/libpg_query/grammar/statements/select.y" + case 1196: +#line 3556 "third_party/libpg_query/grammar/statements/select.y" { (yyval.subquerytype) = PG_ANY_SUBLINK; ;} break; - case 1187: -#line 3497 "third_party/libpg_query/grammar/statements/select.y" + case 1197: +#line 3557 "third_party/libpg_query/grammar/statements/select.y" { (yyval.subquerytype) = PG_ANY_SUBLINK; ;} break; - case 1188: -#line 3498 "third_party/libpg_query/grammar/statements/select.y" + case 1198: +#line 3558 "third_party/libpg_query/grammar/statements/select.y" { (yyval.subquerytype) = PG_ALL_SUBLINK; ;} break; - case 1189: -#line 3501 "third_party/libpg_query/grammar/statements/select.y" + case 1199: +#line 3561 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1190: -#line 3502 "third_party/libpg_query/grammar/statements/select.y" + case 1200: +#line 3562 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) (yyvsp[(1) - (1)].conststr); ;} break; - case 1191: -#line 3505 "third_party/libpg_query/grammar/statements/select.y" + case 1201: +#line 3565 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "+"; ;} break; - case 1192: -#line 3506 "third_party/libpg_query/grammar/statements/select.y" + case 1202: +#line 3566 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "-"; ;} break; - case 1193: -#line 3507 "third_party/libpg_query/grammar/statements/select.y" + case 1203: +#line 3567 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "*"; ;} break; - case 1194: -#line 3508 "third_party/libpg_query/grammar/statements/select.y" + case 1204: +#line 3568 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "/"; ;} break; - case 1195: -#line 3509 "third_party/libpg_query/grammar/statements/select.y" + case 1205: +#line 3569 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "//"; ;} break; - case 1196: -#line 3510 "third_party/libpg_query/grammar/statements/select.y" + case 1206: +#line 3570 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "%"; ;} break; - case 1197: -#line 3511 "third_party/libpg_query/grammar/statements/select.y" + case 1207: +#line 3571 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "^"; ;} break; - case 1198: -#line 3512 "third_party/libpg_query/grammar/statements/select.y" + case 1208: +#line 3572 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "**"; ;} break; - case 1199: -#line 3513 "third_party/libpg_query/grammar/statements/select.y" + case 1209: +#line 3573 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "<"; ;} break; - case 1200: -#line 3514 "third_party/libpg_query/grammar/statements/select.y" + case 1210: +#line 3574 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = ">"; ;} break; - case 1201: -#line 3515 "third_party/libpg_query/grammar/statements/select.y" + case 1211: +#line 3575 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "="; ;} break; - case 1202: -#line 3516 "third_party/libpg_query/grammar/statements/select.y" + case 1212: +#line 3576 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "<="; ;} break; - case 1203: -#line 3517 "third_party/libpg_query/grammar/statements/select.y" + case 1213: +#line 3577 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = ">="; ;} break; - case 1204: -#line 3518 "third_party/libpg_query/grammar/statements/select.y" + case 1214: +#line 3578 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "<>"; ;} break; - case 1205: -#line 3522 "third_party/libpg_query/grammar/statements/select.y" + case 1215: +#line 3582 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1206: -#line 3524 "third_party/libpg_query/grammar/statements/select.y" + case 1216: +#line 3584 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1207: -#line 3529 "third_party/libpg_query/grammar/statements/select.y" + case 1217: +#line 3589 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1208: -#line 3531 "third_party/libpg_query/grammar/statements/select.y" + case 1218: +#line 3591 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1209: -#line 3536 "third_party/libpg_query/grammar/statements/select.y" + case 1219: +#line 3596 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1210: -#line 3538 "third_party/libpg_query/grammar/statements/select.y" + case 1220: +#line 3598 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1211: -#line 3540 "third_party/libpg_query/grammar/statements/select.y" + case 1221: +#line 3600 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("~~")); ;} break; - case 1212: -#line 3542 "third_party/libpg_query/grammar/statements/select.y" + case 1222: +#line 3602 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("!~~")); ;} break; - case 1213: -#line 3544 "third_party/libpg_query/grammar/statements/select.y" + case 1223: +#line 3604 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("~~~")); ;} break; - case 1214: -#line 3546 "third_party/libpg_query/grammar/statements/select.y" + case 1224: +#line 3606 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("!~~~")); ;} break; - case 1215: -#line 3548 "third_party/libpg_query/grammar/statements/select.y" + case 1225: +#line 3608 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("~~*")); ;} break; - case 1216: -#line 3550 "third_party/libpg_query/grammar/statements/select.y" + case 1226: +#line 3610 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("!~~*")); ;} break; - case 1217: -#line 3564 "third_party/libpg_query/grammar/statements/select.y" + case 1227: +#line 3624 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1218: -#line 3566 "third_party/libpg_query/grammar/statements/select.y" + case 1228: +#line 3626 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lcons(makeString((yyvsp[(1) - (3)].str)), (yyvsp[(3) - (3)].list)); ;} break; - case 1219: -#line 3571 "third_party/libpg_query/grammar/statements/select.y" + case 1229: +#line 3631 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1220: -#line 3575 "third_party/libpg_query/grammar/statements/select.y" + case 1230: +#line 3635 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1221: -#line 3582 "third_party/libpg_query/grammar/statements/select.y" + case 1231: +#line 3642 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1222: -#line 3587 "third_party/libpg_query/grammar/statements/select.y" + case 1232: +#line 3647 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1223: -#line 3593 "third_party/libpg_query/grammar/statements/select.y" + case 1233: +#line 3653 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1224: -#line 3597 "third_party/libpg_query/grammar/statements/select.y" + case 1234: +#line 3657 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1225: -#line 3604 "third_party/libpg_query/grammar/statements/select.y" + case 1235: +#line 3664 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1226: -#line 3609 "third_party/libpg_query/grammar/statements/select.y" + case 1236: +#line 3669 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1227: -#line 3616 "third_party/libpg_query/grammar/statements/select.y" + case 1237: +#line 3676 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1228: -#line 3620 "third_party/libpg_query/grammar/statements/select.y" + case 1238: +#line 3680 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1229: -#line 3629 "third_party/libpg_query/grammar/statements/select.y" + case 1239: +#line 3689 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1230: -#line 3633 "third_party/libpg_query/grammar/statements/select.y" + case 1240: +#line 3693 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1231: -#line 3639 "third_party/libpg_query/grammar/statements/select.y" + case 1241: +#line 3699 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1232: -#line 3643 "third_party/libpg_query/grammar/statements/select.y" + case 1242: +#line 3703 "third_party/libpg_query/grammar/statements/select.y" { PGNamedArgExpr *na = makeNode(PGNamedArgExpr); na->name = (yyvsp[(1) - (3)].str); @@ -30174,8 +30474,8 @@ YYLTYPE yylloc; ;} break; - case 1233: -#line 3652 "third_party/libpg_query/grammar/statements/select.y" + case 1243: +#line 3712 "third_party/libpg_query/grammar/statements/select.y" { PGNamedArgExpr *na = makeNode(PGNamedArgExpr); na->name = (yyvsp[(1) - (3)].str); @@ -30186,156 +30486,156 @@ YYLTYPE yylloc; ;} break; - case 1234: -#line 3662 "third_party/libpg_query/grammar/statements/select.y" + case 1244: +#line 3722 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].typnam)); ;} break; - case 1235: -#line 3663 "third_party/libpg_query/grammar/statements/select.y" + case 1245: +#line 3723 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].typnam)); ;} break; - case 1236: -#line 3668 "third_party/libpg_query/grammar/statements/select.y" + case 1246: +#line 3728 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(makeStringConst((yyvsp[(1) - (3)].str), (yylsp[(1) - (3)])), (yyvsp[(3) - (3)].node)); ;} break; - case 1237: -#line 3671 "third_party/libpg_query/grammar/statements/select.y" + case 1247: +#line 3731 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1238: -#line 3678 "third_party/libpg_query/grammar/statements/select.y" + case 1248: +#line 3738 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1239: -#line 3679 "third_party/libpg_query/grammar/statements/select.y" + case 1249: +#line 3739 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "year"; ;} break; - case 1240: -#line 3680 "third_party/libpg_query/grammar/statements/select.y" + case 1250: +#line 3740 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "month"; ;} break; - case 1241: -#line 3681 "third_party/libpg_query/grammar/statements/select.y" + case 1251: +#line 3741 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "day"; ;} break; - case 1242: -#line 3682 "third_party/libpg_query/grammar/statements/select.y" + case 1252: +#line 3742 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "hour"; ;} break; - case 1243: -#line 3683 "third_party/libpg_query/grammar/statements/select.y" + case 1253: +#line 3743 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "minute"; ;} break; - case 1244: -#line 3684 "third_party/libpg_query/grammar/statements/select.y" + case 1254: +#line 3744 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "second"; ;} break; - case 1245: -#line 3685 "third_party/libpg_query/grammar/statements/select.y" + case 1255: +#line 3745 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "millisecond"; ;} break; - case 1246: -#line 3686 "third_party/libpg_query/grammar/statements/select.y" + case 1256: +#line 3746 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "microsecond"; ;} break; - case 1247: -#line 3687 "third_party/libpg_query/grammar/statements/select.y" + case 1257: +#line 3747 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "week"; ;} break; - case 1248: -#line 3688 "third_party/libpg_query/grammar/statements/select.y" + case 1258: +#line 3748 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "quarter"; ;} break; - case 1249: -#line 3689 "third_party/libpg_query/grammar/statements/select.y" + case 1259: +#line 3749 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "decade"; ;} break; - case 1250: -#line 3690 "third_party/libpg_query/grammar/statements/select.y" + case 1260: +#line 3750 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "century"; ;} break; - case 1251: -#line 3691 "third_party/libpg_query/grammar/statements/select.y" + case 1261: +#line 3751 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "millennium"; ;} break; - case 1252: -#line 3692 "third_party/libpg_query/grammar/statements/select.y" + case 1262: +#line 3752 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1253: -#line 3703 "third_party/libpg_query/grammar/statements/select.y" + case 1263: +#line 3763 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make4((yyvsp[(1) - (4)].node), (yyvsp[(2) - (4)].node), (yyvsp[(3) - (4)].node), (yyvsp[(4) - (4)].node)); ;} break; - case 1254: -#line 3707 "third_party/libpg_query/grammar/statements/select.y" + case 1264: +#line 3767 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make3((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1255: -#line 3714 "third_party/libpg_query/grammar/statements/select.y" + case 1265: +#line 3774 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1256: -#line 3720 "third_party/libpg_query/grammar/statements/select.y" + case 1266: +#line 3780 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1257: -#line 3721 "third_party/libpg_query/grammar/statements/select.y" + case 1267: +#line 3781 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1258: -#line 3738 "third_party/libpg_query/grammar/statements/select.y" + case 1268: +#line 3798 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make3((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1259: -#line 3742 "third_party/libpg_query/grammar/statements/select.y" + case 1269: +#line 3802 "third_party/libpg_query/grammar/statements/select.y" { /* not legal per SQL99, but might as well allow it */ (yyval.list) = list_make3((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yyvsp[(2) - (3)].node)); ;} break; - case 1260: -#line 3747 "third_party/libpg_query/grammar/statements/select.y" + case 1270: +#line 3807 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); ;} break; - case 1261: -#line 3751 "third_party/libpg_query/grammar/statements/select.y" + case 1271: +#line 3811 "third_party/libpg_query/grammar/statements/select.y" { /* * Since there are no cases where this syntax allows @@ -30352,45 +30652,45 @@ YYLTYPE yylloc; ;} break; - case 1262: -#line 3766 "third_party/libpg_query/grammar/statements/select.y" + case 1272: +#line 3826 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1263: -#line 3770 "third_party/libpg_query/grammar/statements/select.y" + case 1273: +#line 3830 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1264: -#line 3774 "third_party/libpg_query/grammar/statements/select.y" + case 1274: +#line 3834 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1265: -#line 3777 "third_party/libpg_query/grammar/statements/select.y" + case 1275: +#line 3837 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1266: -#line 3780 "third_party/libpg_query/grammar/statements/select.y" + case 1276: +#line 3840 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(3) - (3)].list), (yyvsp[(1) - (3)].node)); ;} break; - case 1267: -#line 3781 "third_party/libpg_query/grammar/statements/select.y" + case 1277: +#line 3841 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1268: -#line 3782 "third_party/libpg_query/grammar/statements/select.y" + case 1278: +#line 3842 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1269: -#line 3786 "third_party/libpg_query/grammar/statements/select.y" + case 1279: +#line 3846 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subselect = (yyvsp[(1) - (1)].node); @@ -30399,18 +30699,18 @@ YYLTYPE yylloc; ;} break; - case 1270: -#line 3792 "third_party/libpg_query/grammar/statements/select.y" + case 1280: +#line 3852 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *)(yyvsp[(2) - (3)].list); ;} break; - case 1272: -#line 3794 "third_party/libpg_query/grammar/statements/select.y" + case 1282: +#line 3854 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *)(yyvsp[(1) - (1)].node); ;} break; - case 1273: -#line 3805 "third_party/libpg_query/grammar/statements/select.y" + case 1283: +#line 3865 "third_party/libpg_query/grammar/statements/select.y" { PGCaseExpr *c = makeNode(PGCaseExpr); c->casetype = InvalidOid; /* not analyzed yet */ @@ -30422,18 +30722,18 @@ YYLTYPE yylloc; ;} break; - case 1274: -#line 3818 "third_party/libpg_query/grammar/statements/select.y" + case 1284: +#line 3878 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1275: -#line 3819 "third_party/libpg_query/grammar/statements/select.y" + case 1285: +#line 3879 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 1276: -#line 3824 "third_party/libpg_query/grammar/statements/select.y" + case 1286: +#line 3884 "third_party/libpg_query/grammar/statements/select.y" { PGCaseWhen *w = makeNode(PGCaseWhen); w->expr = (PGExpr *) (yyvsp[(2) - (4)].node); @@ -30443,49 +30743,49 @@ YYLTYPE yylloc; ;} break; - case 1277: -#line 3834 "third_party/libpg_query/grammar/statements/select.y" + case 1287: +#line 3894 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1278: -#line 3835 "third_party/libpg_query/grammar/statements/select.y" + case 1288: +#line 3895 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1279: -#line 3838 "third_party/libpg_query/grammar/statements/select.y" + case 1289: +#line 3898 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1280: -#line 3839 "third_party/libpg_query/grammar/statements/select.y" + case 1290: +#line 3899 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1281: -#line 3848 "third_party/libpg_query/grammar/statements/select.y" + case 1291: +#line 3908 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (1)].str), NIL, (yylsp[(1) - (1)]), yyscanner); ;} break; - case 1282: -#line 3854 "third_party/libpg_query/grammar/statements/select.y" + case 1292: +#line 3914 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (1)].str), NIL, (yylsp[(1) - (1)]), yyscanner); ;} break; - case 1283: -#line 3858 "third_party/libpg_query/grammar/statements/select.y" + case 1293: +#line 3918 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].list), (yylsp[(1) - (2)]), yyscanner); ;} break; - case 1284: -#line 3865 "third_party/libpg_query/grammar/statements/select.y" + case 1294: +#line 3925 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = false; @@ -30495,8 +30795,8 @@ YYLTYPE yylloc; ;} break; - case 1285: -#line 3873 "third_party/libpg_query/grammar/statements/select.y" + case 1295: +#line 3933 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -30506,8 +30806,8 @@ YYLTYPE yylloc; ;} break; - case 1286: -#line 3880 "third_party/libpg_query/grammar/statements/select.y" + case 1296: +#line 3940 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -30518,8 +30818,8 @@ YYLTYPE yylloc; ;} break; - case 1287: -#line 3888 "third_party/libpg_query/grammar/statements/select.y" + case 1297: +#line 3948 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -30529,43 +30829,43 @@ YYLTYPE yylloc; ;} break; - case 1288: -#line 3898 "third_party/libpg_query/grammar/statements/select.y" + case 1298: +#line 3958 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1289: -#line 3899 "third_party/libpg_query/grammar/statements/select.y" + case 1299: +#line 3959 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1290: -#line 3904 "third_party/libpg_query/grammar/statements/select.y" + case 1300: +#line 3964 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1291: -#line 3905 "third_party/libpg_query/grammar/statements/select.y" + case 1301: +#line 3965 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 1292: -#line 3909 "third_party/libpg_query/grammar/statements/select.y" + case 1302: +#line 3969 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1293: -#line 3910 "third_party/libpg_query/grammar/statements/select.y" + case 1303: +#line 3970 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(NULL); ;} break; - case 1294: -#line 3911 "third_party/libpg_query/grammar/statements/select.y" + case 1304: +#line 3971 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1295: -#line 3916 "third_party/libpg_query/grammar/statements/select.y" + case 1305: +#line 3976 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(3) - (3)].list)) { PGFuncCall *n = makeFuncCall(list_make1(makeString((yyvsp[(2) - (3)].str))), (yyvsp[(3) - (3)].list)->head->data.ptr_value ? (yyvsp[(3) - (3)].list) : NULL, (yylsp[(2) - (3)])); @@ -30576,8 +30876,8 @@ YYLTYPE yylloc; ;} break; - case 1296: -#line 3925 "third_party/libpg_query/grammar/statements/select.y" + case 1306: +#line 3985 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = false; @@ -30587,8 +30887,8 @@ YYLTYPE yylloc; ;} break; - case 1297: -#line 3933 "third_party/libpg_query/grammar/statements/select.y" + case 1307: +#line 3993 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -30598,8 +30898,8 @@ YYLTYPE yylloc; ;} break; - case 1298: -#line 3940 "third_party/libpg_query/grammar/statements/select.y" + case 1308: +#line 4000 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -30610,8 +30910,8 @@ YYLTYPE yylloc; ;} break; - case 1299: -#line 3949 "third_party/libpg_query/grammar/statements/select.y" + case 1309: +#line 4009 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -30621,48 +30921,48 @@ YYLTYPE yylloc; ;} break; - case 1300: -#line 3964 "third_party/libpg_query/grammar/statements/select.y" + case 1310: +#line 4024 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1301: -#line 3965 "third_party/libpg_query/grammar/statements/select.y" + case 1311: +#line 4025 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 1304: -#line 3981 "third_party/libpg_query/grammar/statements/select.y" + case 1314: +#line 4041 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1305: -#line 3982 "third_party/libpg_query/grammar/statements/select.y" + case 1315: +#line 4042 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1306: -#line 3986 "third_party/libpg_query/grammar/statements/select.y" + case 1316: +#line 4046 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].target)); ;} break; - case 1307: -#line 3987 "third_party/libpg_query/grammar/statements/select.y" + case 1317: +#line 4047 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].target)); ;} break; - case 1308: -#line 3991 "third_party/libpg_query/grammar/statements/select.y" + case 1318: +#line 4051 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1309: -#line 3992 "third_party/libpg_query/grammar/statements/select.y" + case 1319: +#line 4052 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1310: -#line 3996 "third_party/libpg_query/grammar/statements/select.y" + case 1320: +#line 4056 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = (yyvsp[(3) - (3)].str); @@ -30672,8 +30972,8 @@ YYLTYPE yylloc; ;} break; - case 1311: -#line 4012 "third_party/libpg_query/grammar/statements/select.y" + case 1321: +#line 4072 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = (yyvsp[(2) - (2)].str); @@ -30683,8 +30983,8 @@ YYLTYPE yylloc; ;} break; - case 1312: -#line 4020 "third_party/libpg_query/grammar/statements/select.y" + case 1322: +#line 4080 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = NULL; @@ -30694,8 +30994,8 @@ YYLTYPE yylloc; ;} break; - case 1313: -#line 4028 "third_party/libpg_query/grammar/statements/select.y" + case 1323: +#line 4088 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = (yyvsp[(1) - (3)].str); @@ -30705,214 +31005,214 @@ YYLTYPE yylloc; ;} break; - case 1314: -#line 4037 "third_party/libpg_query/grammar/statements/select.y" + case 1324: +#line 4097 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1315: -#line 4038 "third_party/libpg_query/grammar/statements/select.y" + case 1325: +#line 4098 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(2) - (2)].list)); ;} break; - case 1316: -#line 4043 "third_party/libpg_query/grammar/statements/select.y" + case 1326: +#line 4103 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].str)); ;} break; - case 1317: -#line 4047 "third_party/libpg_query/grammar/statements/select.y" + case 1327: +#line 4107 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].str)); ;} break; - case 1318: -#line 4053 "third_party/libpg_query/grammar/statements/select.y" + case 1328: +#line 4113 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 1319: -#line 4055 "third_party/libpg_query/grammar/statements/select.y" + case 1329: +#line 4115 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 1320: -#line 4059 "third_party/libpg_query/grammar/statements/select.y" + case 1330: +#line 4119 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1321: -#line 4060 "third_party/libpg_query/grammar/statements/select.y" + case 1331: +#line 4120 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1322: -#line 4064 "third_party/libpg_query/grammar/statements/select.y" + case 1332: +#line 4124 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1323: -#line 4065 "third_party/libpg_query/grammar/statements/select.y" + case 1333: +#line 4125 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1324: -#line 4068 "third_party/libpg_query/grammar/statements/select.y" + case 1334: +#line 4128 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 1325: -#line 4072 "third_party/libpg_query/grammar/statements/select.y" + case 1335: +#line 4132 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 1326: -#line 4073 "third_party/libpg_query/grammar/statements/select.y" + case 1336: +#line 4133 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 1327: -#line 4077 "third_party/libpg_query/grammar/statements/select.y" + case 1337: +#line 4137 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1328: -#line 4078 "third_party/libpg_query/grammar/statements/select.y" + case 1338: +#line 4138 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1329: -#line 4081 "third_party/libpg_query/grammar/statements/select.y" + case 1339: +#line 4141 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1330: -#line 4082 "third_party/libpg_query/grammar/statements/select.y" + case 1340: +#line 4142 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(2) - (2)].list)); ;} break; - case 1331: -#line 4083 "third_party/libpg_query/grammar/statements/select.y" + case 1341: +#line 4143 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1332: -#line 4086 "third_party/libpg_query/grammar/statements/select.y" + case 1342: +#line 4146 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].str)); ;} break; - case 1333: -#line 4090 "third_party/libpg_query/grammar/statements/select.y" + case 1343: +#line 4150 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 1334: -#line 4091 "third_party/libpg_query/grammar/statements/select.y" + case 1344: +#line 4151 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 1335: -#line 4095 "third_party/libpg_query/grammar/statements/select.y" + case 1345: +#line 4155 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1336: -#line 4096 "third_party/libpg_query/grammar/statements/select.y" + case 1346: +#line 4156 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1337: -#line 4098 "third_party/libpg_query/grammar/statements/select.y" + case 1347: +#line 4158 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1338: -#line 4099 "third_party/libpg_query/grammar/statements/select.y" + case 1348: +#line 4159 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(2) - (2)].list)); ;} break; - case 1339: -#line 4100 "third_party/libpg_query/grammar/statements/select.y" + case 1349: +#line 4160 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1340: -#line 4110 "third_party/libpg_query/grammar/statements/select.y" + case 1350: +#line 4170 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].range)); ;} break; - case 1341: -#line 4111 "third_party/libpg_query/grammar/statements/select.y" + case 1351: +#line 4171 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].range)); ;} break; - case 1342: -#line 4116 "third_party/libpg_query/grammar/statements/select.y" + case 1352: +#line 4176 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1343: -#line 4118 "third_party/libpg_query/grammar/statements/select.y" + case 1353: +#line 4178 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 1344: -#line 4123 "third_party/libpg_query/grammar/statements/select.y" + case 1354: +#line 4183 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1345: -#line 4124 "third_party/libpg_query/grammar/statements/select.y" + case 1355: +#line 4184 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1346: -#line 4128 "third_party/libpg_query/grammar/statements/select.y" + case 1356: +#line 4188 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1347: -#line 4129 "third_party/libpg_query/grammar/statements/select.y" + case 1357: +#line 4189 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1348: -#line 4132 "third_party/libpg_query/grammar/statements/select.y" + case 1358: +#line 4192 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1349: -#line 4144 "third_party/libpg_query/grammar/statements/select.y" + case 1359: +#line 4204 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1350: -#line 4147 "third_party/libpg_query/grammar/statements/select.y" + case 1360: +#line 4207 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = check_func_name(lcons(makeString((yyvsp[(1) - (2)].str)), (yyvsp[(2) - (2)].list)), yyscanner); ;} break; - case 1351: -#line 4158 "third_party/libpg_query/grammar/statements/select.y" + case 1361: +#line 4218 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival), (yylsp[(1) - (1)])); ;} break; - case 1352: -#line 4162 "third_party/libpg_query/grammar/statements/select.y" + case 1362: +#line 4222 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1353: -#line 4166 "third_party/libpg_query/grammar/statements/select.y" + case 1363: +#line 4226 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].list)) { @@ -30926,15 +31226,15 @@ YYLTYPE yylloc; ;} break; - case 1354: -#line 4178 "third_party/libpg_query/grammar/statements/select.y" + case 1364: +#line 4238 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeBitStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1355: -#line 4182 "third_party/libpg_query/grammar/statements/select.y" + case 1365: +#line 4242 "third_party/libpg_query/grammar/statements/select.y" { /* This is a bit constant per SQL99: * Without Feature F511, "BIT data type", @@ -30945,8 +31245,8 @@ YYLTYPE yylloc; ;} break; - case 1356: -#line 4191 "third_party/libpg_query/grammar/statements/select.y" + case 1366: +#line 4251 "third_party/libpg_query/grammar/statements/select.y" { /* generic type 'literal' syntax */ PGTypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (2)].list)); @@ -30955,8 +31255,8 @@ YYLTYPE yylloc; ;} break; - case 1357: -#line 4198 "third_party/libpg_query/grammar/statements/select.y" + case 1367: +#line 4258 "third_party/libpg_query/grammar/statements/select.y" { /* generic syntax with a type modifier */ PGTypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (7)].list)); @@ -30996,146 +31296,146 @@ YYLTYPE yylloc; ;} break; - case 1358: -#line 4236 "third_party/libpg_query/grammar/statements/select.y" + case 1368: +#line 4296 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeStringConstCast((yyvsp[(2) - (2)].str), (yylsp[(2) - (2)]), (yyvsp[(1) - (2)].typnam)); ;} break; - case 1359: -#line 4240 "third_party/libpg_query/grammar/statements/select.y" + case 1369: +#line 4300 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntervalNode((yyvsp[(3) - (5)].node), (yylsp[(3) - (5)]), (yyvsp[(5) - (5)].list)); ;} break; - case 1360: -#line 4244 "third_party/libpg_query/grammar/statements/select.y" + case 1370: +#line 4304 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntervalNode((yyvsp[(2) - (3)].ival), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].list)); ;} break; - case 1361: -#line 4248 "third_party/libpg_query/grammar/statements/select.y" + case 1371: +#line 4308 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntervalNode((yyvsp[(2) - (3)].str), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].list)); ;} break; - case 1362: -#line 4252 "third_party/libpg_query/grammar/statements/select.y" + case 1372: +#line 4312 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeBoolAConst(true, (yylsp[(1) - (1)])); ;} break; - case 1363: -#line 4256 "third_party/libpg_query/grammar/statements/select.y" + case 1373: +#line 4316 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeBoolAConst(false, (yylsp[(1) - (1)])); ;} break; - case 1364: -#line 4260 "third_party/libpg_query/grammar/statements/select.y" + case 1374: +#line 4320 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNullAConst((yylsp[(1) - (1)])); ;} break; - case 1365: -#line 4265 "third_party/libpg_query/grammar/statements/select.y" + case 1375: +#line 4325 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;} break; - case 1366: -#line 4282 "third_party/libpg_query/grammar/statements/select.y" + case 1376: +#line 4342 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1367: -#line 4283 "third_party/libpg_query/grammar/statements/select.y" + case 1377: +#line 4343 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1368: -#line 4284 "third_party/libpg_query/grammar/statements/select.y" + case 1378: +#line 4344 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1369: -#line 4287 "third_party/libpg_query/grammar/statements/select.y" + case 1379: +#line 4347 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1370: -#line 4288 "third_party/libpg_query/grammar/statements/select.y" + case 1380: +#line 4348 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1371: -#line 4289 "third_party/libpg_query/grammar/statements/select.y" + case 1381: +#line 4349 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1372: -#line 4292 "third_party/libpg_query/grammar/statements/select.y" + case 1382: +#line 4352 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1373: -#line 4293 "third_party/libpg_query/grammar/statements/select.y" + case 1383: +#line 4353 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1374: -#line 4294 "third_party/libpg_query/grammar/statements/select.y" + case 1384: +#line 4354 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1375: -#line 4297 "third_party/libpg_query/grammar/statements/select.y" + case 1385: +#line 4357 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1376: -#line 4298 "third_party/libpg_query/grammar/statements/select.y" + case 1386: +#line 4358 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lcons(makeString((yyvsp[(1) - (2)].str)), (yyvsp[(2) - (2)].list)); ;} break; - case 1377: -#line 4302 "third_party/libpg_query/grammar/statements/select.y" + case 1387: +#line 4362 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(2) - (2)].str))); ;} break; - case 1378: -#line 4304 "third_party/libpg_query/grammar/statements/select.y" + case 1388: +#line 4364 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 1379: -#line 4308 "third_party/libpg_query/grammar/statements/select.y" + case 1389: +#line 4368 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1380: -#line 4309 "third_party/libpg_query/grammar/statements/select.y" + case 1390: +#line 4369 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1382: -#line 4316 "third_party/libpg_query/grammar/statements/select.y" + case 1392: +#line 4376 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1383: -#line 4317 "third_party/libpg_query/grammar/statements/select.y" + case 1393: +#line 4377 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1384: + case 1394: #line 8 "third_party/libpg_query/grammar/statements/prepare.y" { PGPrepareStmt *n = makeNode(PGPrepareStmt); @@ -31146,17 +31446,17 @@ YYLTYPE yylloc; ;} break; - case 1385: + case 1395: #line 18 "third_party/libpg_query/grammar/statements/prepare.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1386: + case 1396: #line 19 "third_party/libpg_query/grammar/statements/prepare.y" { (yyval.list) = NIL; ;} break; - case 1393: + case 1403: #line 8 "third_party/libpg_query/grammar/statements/create_schema.y" { PGCreateSchemaStmt *n = makeNode(PGCreateSchemaStmt); @@ -31178,7 +31478,7 @@ YYLTYPE yylloc; ;} break; - case 1394: + case 1404: #line 27 "third_party/libpg_query/grammar/statements/create_schema.y" { PGCreateSchemaStmt *n = makeNode(PGCreateSchemaStmt); @@ -31205,7 +31505,7 @@ YYLTYPE yylloc; ;} break; - case 1395: + case 1405: #line 51 "third_party/libpg_query/grammar/statements/create_schema.y" { PGCreateSchemaStmt *n = makeNode(PGCreateSchemaStmt); @@ -31227,7 +31527,7 @@ YYLTYPE yylloc; ;} break; - case 1396: + case 1406: #line 74 "third_party/libpg_query/grammar/statements/create_schema.y" { if ((yyloc) < 0) /* see comments for YYLLOC_DEFAULT */ @@ -31236,12 +31536,12 @@ YYLTYPE yylloc; ;} break; - case 1397: + case 1407: #line 80 "third_party/libpg_query/grammar/statements/create_schema.y" { (yyval.list) = NIL; ;} break; - case 1402: + case 1412: #line 11 "third_party/libpg_query/grammar/statements/index.y" { PGIndexStmt *n = makeNode(PGIndexStmt); @@ -31267,7 +31567,7 @@ YYLTYPE yylloc; ;} break; - case 1403: + case 1413: #line 36 "third_party/libpg_query/grammar/statements/index.y" { PGIndexStmt *n = makeNode(PGIndexStmt); @@ -31293,62 +31593,62 @@ YYLTYPE yylloc; ;} break; - case 1404: + case 1414: #line 62 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1405: + case 1415: #line 66 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1406: + case 1416: #line 67 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (char*) DEFAULT_INDEX_TYPE; ;} break; - case 1407: + case 1417: #line 72 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = true; ;} break; - case 1408: + case 1418: #line 73 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = false; ;} break; - case 1409: + case 1419: #line 78 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1410: + case 1420: #line 79 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = NULL; ;} break; - case 1411: + case 1421: #line 83 "third_party/libpg_query/grammar/statements/index.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1412: + case 1422: #line 84 "third_party/libpg_query/grammar/statements/index.y" { (yyval.list) = NIL; ;} break; - case 1413: + case 1423: #line 89 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = true; ;} break; - case 1414: + case 1424: #line 90 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = false; ;} break; - case 1415: + case 1425: #line 8 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -31360,7 +31660,7 @@ YYLTYPE yylloc; ;} break; - case 1416: + case 1426: #line 17 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -31372,7 +31672,7 @@ YYLTYPE yylloc; ;} break; - case 1417: + case 1427: #line 26 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -31384,7 +31684,7 @@ YYLTYPE yylloc; ;} break; - case 1418: + case 1428: #line 35 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -31396,7 +31696,7 @@ YYLTYPE yylloc; ;} break; - case 1419: + case 1429: #line 44 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -31408,7 +31708,7 @@ YYLTYPE yylloc; ;} break; - case 1420: + case 1430: #line 53 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -31420,7 +31720,7 @@ YYLTYPE yylloc; ;} break; - case 1421: + case 1431: #line 6 "third_party/libpg_query/grammar/statements/checkpoint.y" { PGCheckPointStmt *n = makeNode(PGCheckPointStmt); @@ -31430,7 +31730,7 @@ YYLTYPE yylloc; ;} break; - case 1422: + case 1432: #line 13 "third_party/libpg_query/grammar/statements/checkpoint.y" { PGCheckPointStmt *n = makeNode(PGCheckPointStmt); @@ -31440,17 +31740,17 @@ YYLTYPE yylloc; ;} break; - case 1423: + case 1433: #line 22 "third_party/libpg_query/grammar/statements/checkpoint.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1424: + case 1434: #line 23 "third_party/libpg_query/grammar/statements/checkpoint.y" { (yyval.str) = NULL; ;} break; - case 1425: + case 1435: #line 8 "third_party/libpg_query/grammar/statements/comment_on.y" { PGCommentOnStmt *n = makeNode(PGCommentOnStmt); @@ -31461,7 +31761,7 @@ YYLTYPE yylloc; ;} break; - case 1426: + case 1436: #line 16 "third_party/libpg_query/grammar/statements/comment_on.y" { PGCommentOnStmt *n = makeNode(PGCommentOnStmt); @@ -31472,67 +31772,67 @@ YYLTYPE yylloc; ;} break; - case 1427: + case 1437: #line 26 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1428: + case 1438: #line 27 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.node) = makeNullAConst((yylsp[(1) - (1)])); ;} break; - case 1429: + case 1439: #line 30 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_TABLE; ;} break; - case 1430: + case 1440: #line 31 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_SEQUENCE; ;} break; - case 1431: + case 1441: #line 32 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_FUNCTION; ;} break; - case 1432: + case 1442: #line 33 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_FUNCTION; ;} break; - case 1433: + case 1443: #line 34 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_TABLE_MACRO; ;} break; - case 1434: + case 1444: #line 35 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_VIEW; ;} break; - case 1435: + case 1445: #line 36 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_DATABASE; ;} break; - case 1436: + case 1446: #line 37 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_INDEX; ;} break; - case 1437: + case 1447: #line 38 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_SCHEMA; ;} break; - case 1438: + case 1448: #line 39 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_TYPE; ;} break; - case 1439: + case 1449: #line 8 "third_party/libpg_query/grammar/statements/export.y" { PGExportStmt *n = makeNode(PGExportStmt); @@ -31546,7 +31846,7 @@ YYLTYPE yylloc; ;} break; - case 1440: + case 1450: #line 20 "third_party/libpg_query/grammar/statements/export.y" { PGExportStmt *n = makeNode(PGExportStmt); @@ -31560,7 +31860,7 @@ YYLTYPE yylloc; ;} break; - case 1441: + case 1451: #line 34 "third_party/libpg_query/grammar/statements/export.y" { PGImportStmt *n = makeNode(PGImportStmt); @@ -31569,7 +31869,7 @@ YYLTYPE yylloc; ;} break; - case 1442: + case 1452: #line 10 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -31579,7 +31879,7 @@ YYLTYPE yylloc; ;} break; - case 1443: + case 1453: #line 17 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -31592,7 +31892,7 @@ YYLTYPE yylloc; ;} break; - case 1444: + case 1454: #line 27 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -31602,7 +31902,7 @@ YYLTYPE yylloc; ;} break; - case 1445: + case 1455: #line 34 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -31612,118 +31912,118 @@ YYLTYPE yylloc; ;} break; - case 1446: + case 1456: #line 44 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.boolean) = true; ;} break; - case 1447: + case 1457: #line 45 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.boolean) = false; ;} break; - case 1448: + case 1458: #line 50 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.node) = (PGNode *) makeString((yyvsp[(1) - (1)].str)); ;} break; - case 1449: + case 1459: #line 51 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.node) = (PGNode *) (yyvsp[(1) - (1)].value); ;} break; - case 1450: + case 1460: #line 52 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.node) = NULL; ;} break; - case 1483: + case 1493: #line 92 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1484: + case 1494: #line 93 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1485: + case 1495: #line 94 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1486: + case 1496: #line 99 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1487: + case 1497: #line 100 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1488: + case 1498: #line 106 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].defelt)); ;} break; - case 1489: + case 1499: #line 110 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].defelt)); ;} break; - case 1490: + case 1500: #line 117 "third_party/libpg_query/grammar/statements/explain.y" {;} break; - case 1491: + case 1501: #line 118 "third_party/libpg_query/grammar/statements/explain.y" {;} break; - case 1492: + case 1502: #line 123 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "true"; ;} break; - case 1493: + case 1503: #line 124 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "false"; ;} break; - case 1494: + case 1504: #line 125 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "on"; ;} break; - case 1495: + case 1505: #line 131 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1496: + case 1506: #line 137 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.defelt) = makeDefElem((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1497: + case 1507: #line 144 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1498: + case 1508: #line 145 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "analyze"; ;} break; - case 1499: + case 1509: #line 11 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(2) - (2)].vsetstmt); @@ -31732,7 +32032,7 @@ YYLTYPE yylloc; ;} break; - case 1500: + case 1510: #line 17 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -31741,7 +32041,7 @@ YYLTYPE yylloc; ;} break; - case 1501: + case 1511: #line 23 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -31750,7 +32050,7 @@ YYLTYPE yylloc; ;} break; - case 1502: + case 1512: #line 29 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -31759,7 +32059,7 @@ YYLTYPE yylloc; ;} break; - case 1503: + case 1513: #line 35 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -31768,12 +32068,12 @@ YYLTYPE yylloc; ;} break; - case 1504: + case 1514: #line 44 "third_party/libpg_query/grammar/statements/variable_set.y" {(yyval.vsetstmt) = (yyvsp[(1) - (1)].vsetstmt);;} break; - case 1505: + case 1515: #line 46 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -31783,7 +32083,7 @@ YYLTYPE yylloc; ;} break; - case 1506: + case 1516: #line 54 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -31797,7 +32097,7 @@ YYLTYPE yylloc; ;} break; - case 1507: + case 1517: #line 65 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -31808,7 +32108,7 @@ YYLTYPE yylloc; ;} break; - case 1508: + case 1518: #line 77 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -31819,7 +32119,7 @@ YYLTYPE yylloc; ;} break; - case 1509: + case 1519: #line 85 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -31830,26 +32130,26 @@ YYLTYPE yylloc; ;} break; - case 1510: + case 1520: #line 96 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1511: + case 1521: #line 102 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1512: + case 1522: #line 106 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1513: + case 1523: #line 110 "third_party/libpg_query/grammar/statements/variable_set.y" { PGTypeName *t = (yyvsp[(1) - (3)].typnam); @@ -31867,7 +32167,7 @@ YYLTYPE yylloc; ;} break; - case 1514: + case 1524: #line 125 "third_party/libpg_query/grammar/statements/variable_set.y" { PGTypeName *t = (yyvsp[(1) - (5)].typnam); @@ -31877,32 +32177,32 @@ YYLTYPE yylloc; ;} break; - case 1515: + case 1525: #line 131 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = makeAConst((yyvsp[(1) - (1)].value), (yylsp[(1) - (1)])); ;} break; - case 1516: + case 1526: #line 132 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = NULL; ;} break; - case 1517: + case 1527: #line 133 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = NULL; ;} break; - case 1518: + case 1528: #line 137 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1519: + case 1529: #line 138 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1520: + case 1530: #line 8 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -31915,7 +32215,7 @@ YYLTYPE yylloc; ;} break; - case 1521: + case 1531: #line 17 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -31928,7 +32228,7 @@ YYLTYPE yylloc; ;} break; - case 1522: + case 1532: #line 26 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -31941,7 +32241,7 @@ YYLTYPE yylloc; ;} break; - case 1523: + case 1533: #line 35 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -31954,42 +32254,42 @@ YYLTYPE yylloc; ;} break; - case 1524: + case 1534: #line 46 "third_party/libpg_query/grammar/statements/load.y" { (yyval.loadinstalltype) = PG_LOAD_TYPE_INSTALL; ;} break; - case 1525: + case 1535: #line 47 "third_party/libpg_query/grammar/statements/load.y" { (yyval.loadinstalltype) = PG_LOAD_TYPE_FORCE_INSTALL; ;} break; - case 1526: + case 1536: #line 49 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1527: + case 1537: #line 50 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1528: + case 1538: #line 53 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = NULL; ;} break; - case 1529: + case 1539: #line 54 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1530: + case 1540: #line 55 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1531: + case 1541: #line 9 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -32006,7 +32306,7 @@ YYLTYPE yylloc; ;} break; - case 1532: + case 1542: #line 23 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -32023,7 +32323,7 @@ YYLTYPE yylloc; ;} break; - case 1533: + case 1543: #line 37 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = (PGVacuumStmt *) (yyvsp[(5) - (5)].node); @@ -32038,7 +32338,7 @@ YYLTYPE yylloc; ;} break; - case 1534: + case 1544: #line 49 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -32049,7 +32349,7 @@ YYLTYPE yylloc; ;} break; - case 1535: + case 1545: #line 57 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -32062,27 +32362,27 @@ YYLTYPE yylloc; ;} break; - case 1536: + case 1546: #line 70 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_ANALYZE; ;} break; - case 1537: + case 1547: #line 71 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_VERBOSE; ;} break; - case 1538: + case 1548: #line 72 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_FREEZE; ;} break; - case 1539: + case 1549: #line 73 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_FULL; ;} break; - case 1540: + case 1550: #line 75 "third_party/libpg_query/grammar/statements/vacuum.y" { if (strcmp((yyvsp[(1) - (1)].str), "disable_page_skipping") == 0) @@ -32095,37 +32395,37 @@ YYLTYPE yylloc; ;} break; - case 1541: + case 1551: #line 87 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = true; ;} break; - case 1542: + case 1552: #line 88 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = false; ;} break; - case 1543: + case 1553: #line 93 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;} break; - case 1544: + case 1554: #line 94 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = (yyvsp[(1) - (3)].ival) | (yyvsp[(3) - (3)].ival); ;} break; - case 1545: + case 1555: #line 98 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = true; ;} break; - case 1546: + case 1556: #line 99 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = false; ;} break; - case 1547: + case 1557: #line 9 "third_party/libpg_query/grammar/statements/delete.y" { PGDeleteStmt *n = makeNode(PGDeleteStmt); @@ -32138,7 +32438,7 @@ YYLTYPE yylloc; ;} break; - case 1548: + case 1558: #line 19 "third_party/libpg_query/grammar/statements/delete.y" { PGDeleteStmt *n = makeNode(PGDeleteStmt); @@ -32151,14 +32451,14 @@ YYLTYPE yylloc; ;} break; - case 1549: + case 1559: #line 32 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.range) = (yyvsp[(1) - (1)].range); ;} break; - case 1550: + case 1560: #line 36 "third_party/libpg_query/grammar/statements/delete.y" { PGAlias *alias = makeNode(PGAlias); @@ -32168,7 +32468,7 @@ YYLTYPE yylloc; ;} break; - case 1551: + case 1561: #line 43 "third_party/libpg_query/grammar/statements/delete.y" { PGAlias *alias = makeNode(PGAlias); @@ -32178,27 +32478,27 @@ YYLTYPE yylloc; ;} break; - case 1552: + case 1562: #line 53 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1553: + case 1563: #line 54 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.node) = NULL; ;} break; - case 1554: + case 1564: #line 60 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1555: + case 1565: #line 61 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.list) = NIL; ;} break; - case 1556: + case 1566: #line 10 "third_party/libpg_query/grammar/statements/analyze.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -32211,7 +32511,7 @@ YYLTYPE yylloc; ;} break; - case 1557: + case 1567: #line 20 "third_party/libpg_query/grammar/statements/analyze.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -32224,7 +32524,7 @@ YYLTYPE yylloc; ;} break; - case 1558: + case 1568: #line 8 "third_party/libpg_query/grammar/statements/attach.y" { PGAttachStmt *n = makeNode(PGAttachStmt); @@ -32236,7 +32536,7 @@ YYLTYPE yylloc; ;} break; - case 1559: + case 1569: #line 17 "third_party/libpg_query/grammar/statements/attach.y" { PGAttachStmt *n = makeNode(PGAttachStmt); @@ -32248,7 +32548,7 @@ YYLTYPE yylloc; ;} break; - case 1560: + case 1570: #line 26 "third_party/libpg_query/grammar/statements/attach.y" { PGAttachStmt *n = makeNode(PGAttachStmt); @@ -32260,7 +32560,7 @@ YYLTYPE yylloc; ;} break; - case 1561: + case 1571: #line 38 "third_party/libpg_query/grammar/statements/attach.y" { PGDetachStmt *n = makeNode(PGDetachStmt); @@ -32270,7 +32570,7 @@ YYLTYPE yylloc; ;} break; - case 1562: + case 1572: #line 45 "third_party/libpg_query/grammar/statements/attach.y" { PGDetachStmt *n = makeNode(PGDetachStmt); @@ -32280,7 +32580,7 @@ YYLTYPE yylloc; ;} break; - case 1563: + case 1573: #line 52 "third_party/libpg_query/grammar/statements/attach.y" { PGDetachStmt *n = makeNode(PGDetachStmt); @@ -32290,72 +32590,72 @@ YYLTYPE yylloc; ;} break; - case 1564: + case 1574: #line 60 "third_party/libpg_query/grammar/statements/attach.y" {;} break; - case 1565: + case 1575: #line 61 "third_party/libpg_query/grammar/statements/attach.y" {;} break; - case 1566: + case 1576: #line 65 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1567: + case 1577: #line 66 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.str) = NULL; ;} break; - case 1568: + case 1578: #line 77 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.node) = (PGNode *) (yyvsp[(1) - (1)].node); ;} break; - case 1569: + case 1579: #line 78 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.node) = NULL; ;} break; - case 1570: + case 1580: #line 83 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.defelt) = makeDefElem((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1571: + case 1581: #line 90 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].defelt)); ;} break; - case 1572: + case 1582: #line 94 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].defelt)); ;} break; - case 1573: + case 1583: #line 101 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1574: + case 1584: #line 105 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.list) = NULL; ;} break; - case 1575: + case 1585: #line 3 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(2) - (2)].vsetstmt)->scope = VAR_SET_SCOPE_DEFAULT; @@ -32363,7 +32663,7 @@ YYLTYPE yylloc; ;} break; - case 1576: + case 1586: #line 8 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_LOCAL; @@ -32371,7 +32671,7 @@ YYLTYPE yylloc; ;} break; - case 1577: + case 1587: #line 13 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_SESSION; @@ -32379,7 +32679,7 @@ YYLTYPE yylloc; ;} break; - case 1578: + case 1588: #line 18 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_GLOBAL; @@ -32387,7 +32687,7 @@ YYLTYPE yylloc; ;} break; - case 1579: + case 1589: #line 23 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_VARIABLE; @@ -32395,7 +32695,7 @@ YYLTYPE yylloc; ;} break; - case 1580: + case 1590: #line 32 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -32405,7 +32705,7 @@ YYLTYPE yylloc; ;} break; - case 1581: + case 1591: #line 39 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -32414,12 +32714,12 @@ YYLTYPE yylloc; ;} break; - case 1582: + case 1592: #line 48 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyval.vsetstmt) = (yyvsp[(1) - (1)].vsetstmt); ;} break; - case 1583: + case 1593: #line 50 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -32429,7 +32729,7 @@ YYLTYPE yylloc; ;} break; - case 1584: + case 1594: #line 57 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -32439,7 +32739,7 @@ YYLTYPE yylloc; ;} break; - case 1585: + case 1595: #line 3 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowSelectStmt *n = makeNode(PGVariableShowSelectStmt); @@ -32450,7 +32750,7 @@ YYLTYPE yylloc; ;} break; - case 1586: + case 1596: #line 10 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowSelectStmt *n = makeNode(PGVariableShowSelectStmt); @@ -32461,7 +32761,7 @@ YYLTYPE yylloc; ;} break; - case 1587: + case 1597: #line 18 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); @@ -32471,7 +32771,7 @@ YYLTYPE yylloc; ;} break; - case 1588: + case 1598: #line 25 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); @@ -32482,7 +32782,7 @@ YYLTYPE yylloc; ;} break; - case 1589: + case 1599: #line 33 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); @@ -32492,7 +32792,7 @@ YYLTYPE yylloc; ;} break; - case 1590: + case 1600: #line 40 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); @@ -32502,7 +32802,7 @@ YYLTYPE yylloc; ;} break; - case 1591: + case 1601: #line 47 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); @@ -32512,7 +32812,7 @@ YYLTYPE yylloc; ;} break; - case 1592: + case 1602: #line 54 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); @@ -32522,7 +32822,7 @@ YYLTYPE yylloc; ;} break; - case 1593: + case 1603: #line 61 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); @@ -32532,17 +32832,17 @@ YYLTYPE yylloc; ;} break; - case 1600: + case 1610: #line 75 "third_party/libpg_query/grammar/statements/variable_show.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1601: + case 1611: #line 77 "third_party/libpg_query/grammar/statements/variable_show.y" { (yyval.str) = psprintf("%s.%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ;} break; - case 1602: + case 1612: #line 7 "third_party/libpg_query/grammar/statements/call.y" { PGCallStmt *n = makeNode(PGCallStmt); @@ -32551,7 +32851,7 @@ YYLTYPE yylloc; ;} break; - case 1603: + case 1613: #line 10 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -32566,7 +32866,7 @@ YYLTYPE yylloc; ;} break; - case 1604: + case 1614: #line 23 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -32581,7 +32881,7 @@ YYLTYPE yylloc; ;} break; - case 1605: + case 1615: #line 36 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -32596,7 +32896,7 @@ YYLTYPE yylloc; ;} break; - case 1606: + case 1616: #line 49 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -32616,7 +32916,7 @@ YYLTYPE yylloc; ;} break; - case 1607: + case 1617: #line 67 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -32636,27 +32936,27 @@ YYLTYPE yylloc; ;} break; - case 1608: + case 1618: #line 87 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = CASCADED_CHECK_OPTION; ;} break; - case 1609: + case 1619: #line 88 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = CASCADED_CHECK_OPTION; ;} break; - case 1610: + case 1620: #line 89 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = PG_LOCAL_CHECK_OPTION; ;} break; - case 1611: + case 1621: #line 90 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = PG_NO_CHECK_OPTION; ;} break; - case 1612: + case 1622: #line 12 "third_party/libpg_query/grammar/statements/create_as.y" { PGCreateTableAsStmt *ctas = makeNode(PGCreateTableAsStmt); @@ -32672,7 +32972,7 @@ YYLTYPE yylloc; ;} break; - case 1613: + case 1623: #line 25 "third_party/libpg_query/grammar/statements/create_as.y" { PGCreateTableAsStmt *ctas = makeNode(PGCreateTableAsStmt); @@ -32688,7 +32988,7 @@ YYLTYPE yylloc; ;} break; - case 1614: + case 1624: #line 38 "third_party/libpg_query/grammar/statements/create_as.y" { PGCreateTableAsStmt *ctas = makeNode(PGCreateTableAsStmt); @@ -32704,29 +33004,38 @@ YYLTYPE yylloc; ;} break; - case 1615: + case 1625: #line 54 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.boolean) = true; ;} break; - case 1616: + case 1626: #line 55 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.boolean) = false; ;} break; - case 1617: + case 1627: #line 56 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.boolean) = true; ;} break; - case 1618: + case 1628: #line 62 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.into) = makeNode(PGIntoClause); - (yyval.into)->rel = (yyvsp[(1) - (4)].range); - (yyval.into)->colNames = (yyvsp[(2) - (4)].list); - (yyval.into)->options = (yyvsp[(3) - (4)].list); - (yyval.into)->onCommit = (yyvsp[(4) - (4)].oncommit); + (yyval.into)->rel = (yyvsp[(1) - (5)].range); + (yyval.into)->colNames = (yyvsp[(2) - (5)].list); + PGListCell *lc; + foreach(lc, (yyvsp[(3) - (5)].list)) { + PGDefElem *de = (PGDefElem *) lfirst(lc); + if (strcmp(de->defname, "partitioned_by") == 0) { + (yyval.into)->partition_list = (PGList *)de->arg; + } else if (strcmp(de->defname, "sorted_by") == 0) { + (yyval.into)->sort_list = (PGList *)de->arg; + } + } + (yyval.into)->options = (yyvsp[(4) - (5)].list); + (yyval.into)->onCommit = (yyvsp[(5) - (5)].oncommit); (yyval.into)->viewQuery = NULL; (yyval.into)->skipData = false; /* might get changed later */ ;} @@ -32734,7 +33043,7 @@ YYLTYPE yylloc; /* Line 1267 of yacc.c. */ -#line 32738 "third_party/libpg_query/grammar/grammar_out.cpp" +#line 33047 "third_party/libpg_query/grammar/grammar_out.cpp" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -32954,7 +33263,7 @@ YYLTYPE yylloc; } -#line 83 "third_party/libpg_query/grammar/statements/create_as.y" +#line 92 "third_party/libpg_query/grammar/statements/create_as.y" #line 1 "third_party/libpg_query/grammar/grammar.cpp" diff --git a/src/duckdb/third_party/mbedtls/include/mbedtls_wrapper.hpp b/src/duckdb/third_party/mbedtls/include/mbedtls_wrapper.hpp index e6e97a717..8633517c9 100644 --- a/src/duckdb/third_party/mbedtls/include/mbedtls_wrapper.hpp +++ b/src/duckdb/third_party/mbedtls/include/mbedtls_wrapper.hpp @@ -47,6 +47,7 @@ class MbedTlsWrapper { private: void *sha_context; + }; static constexpr size_t SHA1_HASH_LENGTH_BYTES = 20; @@ -66,12 +67,12 @@ class MbedTlsWrapper { class AESStateMBEDTLS : public duckdb::EncryptionState { public: - DUCKDB_API explicit AESStateMBEDTLS(duckdb::EncryptionTypes::CipherType cipher_p, duckdb::idx_t key_len); + DUCKDB_API explicit AESStateMBEDTLS(duckdb::unique_ptr metadata); DUCKDB_API ~AESStateMBEDTLS() override; public: - DUCKDB_API void InitializeEncryption(duckdb::const_data_ptr_t iv, duckdb::idx_t iv_len, duckdb::const_data_ptr_t key, duckdb::idx_t key_len, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) override; - DUCKDB_API void InitializeDecryption(duckdb::const_data_ptr_t iv, duckdb::idx_t iv_len, duckdb::const_data_ptr_t key, duckdb::idx_t key_len, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) override; + DUCKDB_API void InitializeEncryption(duckdb::EncryptionNonce &nonce, duckdb::const_data_ptr_t key, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) override; + DUCKDB_API void InitializeDecryption(duckdb::EncryptionNonce &nonce, duckdb::const_data_ptr_t key, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) override; DUCKDB_API size_t Process(duckdb::const_data_ptr_t in, duckdb::idx_t in_len, duckdb::data_ptr_t out, duckdb::idx_t out_len) override; @@ -80,29 +81,55 @@ class AESStateMBEDTLS : public duckdb::EncryptionState { DUCKDB_API static void GenerateRandomDataStatic(duckdb::data_ptr_t data, duckdb::idx_t len); DUCKDB_API void GenerateRandomData(duckdb::data_ptr_t data, duckdb::idx_t len) override; DUCKDB_API void FinalizeGCM(duckdb::data_ptr_t tag, duckdb::idx_t tag_len); - DUCKDB_API const mbedtls_cipher_info_t *GetCipher(size_t key_len); + DUCKDB_API const mbedtls_cipher_info_t *GetCipher(); DUCKDB_API static void SecureClearData(duckdb::data_ptr_t data, duckdb::idx_t len); + public: + void ForceMbedTLSUnsafe() { + force_mbedtls = true; + } + + void UndoForceMbedTLSUnsafe() { + force_mbedtls = false; + } + + private: - DUCKDB_API void InitializeInternal(duckdb::const_data_ptr_t iv, duckdb::idx_t iv_len, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len); + DUCKDB_API void InitializeInternal(duckdb::EncryptionNonce &nonce, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len); + DUCKDB_API void GenerateRandomDataInsecure(duckdb::data_ptr_t data, duckdb::idx_t len); private: duckdb::EncryptionTypes::Mode mode; duckdb::unique_ptr context; + bool force_mbedtls = false; }; class AESStateMBEDTLSFactory : public duckdb::EncryptionUtil { public: - duckdb::shared_ptr CreateEncryptionState(duckdb::EncryptionTypes::CipherType cipher_p, duckdb::idx_t key_len = 0) const override { - return duckdb::make_shared_ptr(cipher_p, key_len); + duckdb::shared_ptr CreateEncryptionState(duckdb::unique_ptr metadata_p) const override { + auto mbedtls_state = duckdb::make_shared_ptr(std::move(metadata_p)); + + if (force_mbedtls_factory) { + mbedtls_state->ForceMbedTLSUnsafe(); + } + + return mbedtls_state; } ~AESStateMBEDTLSFactory() override {} // - DUCKDB_API bool SupportsEncryption() override { - return false; + public: + void ForceMbedTLSUnsafe() { + force_mbedtls_factory = true; } + + void UndoForceMbedTLSUnsafe() { + force_mbedtls_factory = false; + } + + private: + bool force_mbedtls_factory = false; }; }; diff --git a/src/duckdb/third_party/mbedtls/mbedtls_wrapper.cpp b/src/duckdb/third_party/mbedtls/mbedtls_wrapper.cpp index 3a6ce981e..b048ae232 100644 --- a/src/duckdb/third_party/mbedtls/mbedtls_wrapper.cpp +++ b/src/duckdb/third_party/mbedtls/mbedtls_wrapper.cpp @@ -12,11 +12,16 @@ #include "duckdb/common/random_engine.hpp" #include "duckdb/common/types/timestamp.hpp" +#include "duckdb/main/config.hpp" +#include "duckdb/common/encryption_types.hpp" #include using namespace std; using namespace duckdb_mbedtls; +using CipherType = duckdb::EncryptionTypes::CipherType; +using EncryptionVersion = duckdb::EncryptionTypes::EncryptionVersion; +using MainHeader = duckdb::MainHeader; /* # Command line tricks to help here @@ -230,11 +235,10 @@ void MbedTlsWrapper::SHA1State::FinishHex(char *out) { MbedTlsWrapper::ToBase16(const_cast(hash.c_str()), out, MbedTlsWrapper::SHA1_HASH_LENGTH_BYTES); } -const mbedtls_cipher_info_t *MbedTlsWrapper::AESStateMBEDTLS::GetCipher(size_t key_len){ - - switch(cipher){ - case duckdb::EncryptionTypes::CipherType::GCM: - switch (key_len) { +const mbedtls_cipher_info_t *MbedTlsWrapper::AESStateMBEDTLS::GetCipher(){ + switch(metadata->GetCipher()) { + case CipherType::GCM: + switch (metadata->GetKeyLen()) { case 16: return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_GCM); case 24: @@ -244,8 +248,8 @@ const mbedtls_cipher_info_t *MbedTlsWrapper::AESStateMBEDTLS::GetCipher(size_t k default: throw runtime_error("Invalid AES key length for GCM"); } - case duckdb::EncryptionTypes::CipherType::CTR: - switch (key_len) { + case CipherType::CTR: + switch (metadata->GetKeyLen()) { case 16: return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CTR); case 24: @@ -255,8 +259,8 @@ const mbedtls_cipher_info_t *MbedTlsWrapper::AESStateMBEDTLS::GetCipher(size_t k default: throw runtime_error("Invalid AES key length for CTR"); } - case duckdb::EncryptionTypes::CipherType::CBC: - switch (key_len) { + case CipherType::CBC: + switch (metadata->GetKeyLen()) { case 16: return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CBC); case 24: @@ -267,7 +271,7 @@ const mbedtls_cipher_info_t *MbedTlsWrapper::AESStateMBEDTLS::GetCipher(size_t k throw runtime_error("Invalid AES key length for CBC"); } default: - throw duckdb::InternalException("Invalid Encryption/Decryption Cipher: %s", duckdb::EncryptionTypes::CipherToString(cipher)); + throw duckdb::InternalException("Invalid Encryption/Decryption Cipher: %s", duckdb::EncryptionTypes::CipherToString(metadata->GetCipher())); } } @@ -275,10 +279,10 @@ void MbedTlsWrapper::AESStateMBEDTLS::SecureClearData(duckdb::data_ptr_t data, d mbedtls_platform_zeroize(data, len); } -MbedTlsWrapper::AESStateMBEDTLS::AESStateMBEDTLS(duckdb::EncryptionTypes::CipherType cipher_p, duckdb::idx_t key_len) : EncryptionState(cipher_p, key_len), context(duckdb::make_uniq()) { +MbedTlsWrapper::AESStateMBEDTLS::AESStateMBEDTLS(duckdb::unique_ptr metadata_p) : EncryptionState(std::move(metadata_p)), context(duckdb::make_uniq()) { mbedtls_cipher_init(context.get()); - auto cipher_info = GetCipher(key_len); + auto cipher_info = GetCipher(); if (!cipher_info) { throw runtime_error("Failed to get Cipher"); @@ -288,7 +292,7 @@ MbedTlsWrapper::AESStateMBEDTLS::AESStateMBEDTLS(duckdb::EncryptionTypes::Cipher throw runtime_error("Failed to initialize cipher context"); } - if (cipher == duckdb::EncryptionTypes::CBC && mbedtls_cipher_set_padding_mode(context.get(), MBEDTLS_PADDING_PKCS7)) { + if (metadata->GetCipher() == duckdb::EncryptionTypes::CBC && mbedtls_cipher_set_padding_mode(context.get(), MBEDTLS_PADDING_PKCS7)) { throw runtime_error("Failed to set CBC padding"); } @@ -300,16 +304,32 @@ MbedTlsWrapper::AESStateMBEDTLS::~AESStateMBEDTLS() { } } -static void ThrowInsecureRNG() { - throw duckdb::InvalidConfigurationException("DuckDB requires a secure random engine to be loaded to enable secure crypto. Normally, this will be handled automatically by DuckDB by autoloading the `httpfs` Extension, but that seems to have failed. Please ensure the httpfs extension is loaded manually using `LOAD httpfs`."); +void MbedTlsWrapper::AESStateMBEDTLS::GenerateRandomDataInsecure(duckdb::data_ptr_t data, duckdb::idx_t len) { + if (!force_mbedtls) { + // To use this insecure MbedTLS random number generator + // we double check if force_mbedtls_unsafe is set + // such that we do not accidentaly opt-in + throw duckdb::InternalException("Insecure random generation called without setting 'force_mbedtls_unsafe' = true"); + } + + duckdb::RandomEngine random_engine; + + while (len != 0) { + const auto random_integer = random_engine.NextRandomInteger(); + const auto next = duckdb::MinValue(len, sizeof(random_integer)); + memcpy(data, duckdb::const_data_ptr_cast(&random_integer), next); + data += next; + len -= next; + } } void MbedTlsWrapper::AESStateMBEDTLS::GenerateRandomData(duckdb::data_ptr_t data, duckdb::idx_t len) { - ThrowInsecureRNG(); + // generate insecure random data + GenerateRandomDataInsecure(data, len); } -void MbedTlsWrapper::AESStateMBEDTLS::InitializeInternal(duckdb::const_data_ptr_t iv, duckdb::idx_t iv_len, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len){ - if (mbedtls_cipher_set_iv(context.get(), iv, iv_len)) { +void MbedTlsWrapper::AESStateMBEDTLS::InitializeInternal(duckdb::EncryptionNonce &nonce, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len){ + if (mbedtls_cipher_set_iv(context.get(), nonce.data(), nonce.total_size())) { throw runtime_error("Failed to set IV for encryption"); } @@ -320,28 +340,31 @@ void MbedTlsWrapper::AESStateMBEDTLS::InitializeInternal(duckdb::const_data_ptr_ } } -void MbedTlsWrapper::AESStateMBEDTLS::InitializeEncryption(duckdb::const_data_ptr_t iv, duckdb::idx_t iv_len, duckdb::const_data_ptr_t key, duckdb::idx_t key_len_p, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) { - ThrowInsecureRNG(); +void MbedTlsWrapper::AESStateMBEDTLS::InitializeEncryption(duckdb::EncryptionNonce &nonce, duckdb::const_data_ptr_t key, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) { + mode = duckdb::EncryptionTypes::ENCRYPT; + + if (mbedtls_cipher_setkey(context.get(), key, metadata->GetKeyLen() * 8, MBEDTLS_ENCRYPT) != 0) { + runtime_error("Failed to set AES key for encryption"); + } + + InitializeInternal(nonce, aad, aad_len); } -void MbedTlsWrapper::AESStateMBEDTLS::InitializeDecryption(duckdb::const_data_ptr_t iv, duckdb::idx_t iv_len, duckdb::const_data_ptr_t key, duckdb::idx_t key_len_p, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) { +void MbedTlsWrapper::AESStateMBEDTLS::InitializeDecryption(duckdb::EncryptionNonce &nonce, duckdb::const_data_ptr_t key, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) { mode = duckdb::EncryptionTypes::DECRYPT; - if (key_len_p != key_len) { - throw duckdb::InternalException("Invalid encryption key length, expected %llu, got %llu", key_len, key_len_p); - } - if (mbedtls_cipher_setkey(context.get(), key, key_len * 8, MBEDTLS_DECRYPT)) { + if (mbedtls_cipher_setkey(context.get(), key, metadata->GetKeyLen() * 8, MBEDTLS_DECRYPT)) { throw runtime_error("Failed to set AES key for encryption"); } - InitializeInternal(iv, iv_len, aad, aad_len); + InitializeInternal(nonce, aad, aad_len); } size_t MbedTlsWrapper::AESStateMBEDTLS::Process(duckdb::const_data_ptr_t in, duckdb::idx_t in_len, duckdb::data_ptr_t out, duckdb::idx_t out_len) { // GCM works in-place, CTR and CBC don't - auto use_out_copy = in == out && cipher != duckdb::EncryptionTypes::CipherType::GCM; + auto use_out_copy = in == out && metadata->GetCipher() != CipherType::GCM; auto out_ptr = out; std::unique_ptr out_copy; @@ -392,7 +415,7 @@ size_t MbedTlsWrapper::AESStateMBEDTLS::Finalize(duckdb::data_ptr_t out, duckdb: if (mbedtls_cipher_finish(context.get(), out, &result)) { throw runtime_error("Encryption or Decryption failed at Finalize"); } - if (cipher == duckdb::EncryptionTypes::GCM) { + if (metadata->GetCipher() == duckdb::EncryptionTypes::GCM) { FinalizeGCM(tag, tag_len); } return result; diff --git a/src/duckdb/third_party/utf8proc/utf8proc_wrapper.cpp b/src/duckdb/third_party/utf8proc/utf8proc_wrapper.cpp index 7ee4f39c2..7aba4df0f 100644 --- a/src/duckdb/third_party/utf8proc/utf8proc_wrapper.cpp +++ b/src/duckdb/third_party/utf8proc/utf8proc_wrapper.cpp @@ -343,16 +343,20 @@ bool Utf8Proc::CodepointToUtf8(int cp, int &sz, char *c) { int Utf8Proc::CodepointLength(int cp) { if (cp <= 0x7F) { return 1; - } else if (cp <= 0x7FF) { + } + if (cp <= 0x7FF) { return 2; - } else if (0xd800 <= cp && cp <= 0xdfff) { - return -1; - } else if (cp <= 0xFFFF) { + } + if (0xd800 <= cp && cp <= 0xdfff) { + throw InternalException("invalid code point detected in Utf8Proc::CodepointLength (0xd800 to 0xdfff), likely due to invalid UTF-8"); + } + if (cp <= 0xFFFF) { return 3; - } else if (cp <= 0x10FFFF) { + } + if (cp <= 0x10FFFF) { return 4; } - return -1; + throw InternalException("invalid code point detected in Utf8Proc::CodepointLength, likely due to invalid UTF-8"); } int32_t Utf8Proc::UTF8ToCodepoint(const char *u_input, int &sz) { @@ -369,7 +373,7 @@ int32_t Utf8Proc::UTF8ToCodepoint(const char *u_input, int &sz) { return (u0 - 192) * 64 + (u1 - 128); } if (u[0] == 0xed && (u[1] & 0xa0) == 0xa0) { - return -1; // code points, 0xd800 to 0xdfff + throw InternalException("invalid code point detected in Utf8Proc::UTF8ToCodepoint (0xd800 to 0xdfff), likely due to invalid UTF-8"); } unsigned char u2 = u[2]; if (u0 >= 224 && u0 <= 239) { @@ -381,7 +385,7 @@ int32_t Utf8Proc::UTF8ToCodepoint(const char *u_input, int &sz) { sz = 4; return (u0 - 240) * 262144 + (u1 - 128) * 4096 + (u2 - 128) * 64 + (u3 - 128); } - return -1; + throw InternalException("invalid code point detected in Utf8Proc::UTF8ToCodepoint, likely due to invalid UTF-8"); } size_t Utf8Proc::RenderWidth(const char *s, size_t len, size_t pos) { diff --git a/src/duckdb/ub_extension_core_functions_scalar_generic.cpp b/src/duckdb/ub_extension_core_functions_scalar_generic.cpp index 68eb6db63..07f2ee65f 100644 --- a/src/duckdb/ub_extension_core_functions_scalar_generic.cpp +++ b/src/duckdb/ub_extension_core_functions_scalar_generic.cpp @@ -16,7 +16,7 @@ #include "extension/core_functions/scalar/generic/stats.cpp" -#include "extension/core_functions/scalar/generic/typeof.cpp" +#include "extension/core_functions/scalar/generic/type_functions.cpp" #include "extension/core_functions/scalar/generic/system_functions.cpp" diff --git a/src/duckdb/ub_src_catalog_catalog_entry.cpp b/src/duckdb/ub_src_catalog_catalog_entry.cpp index 2e11f6d71..6028f3295 100644 --- a/src/duckdb/ub_src_catalog_catalog_entry.cpp +++ b/src/duckdb/ub_src_catalog_catalog_entry.cpp @@ -1,3 +1,5 @@ +#include "src/catalog/catalog_entry/aggregate_function_catalog_entry.cpp" + #include "src/catalog/catalog_entry/copy_function_catalog_entry.cpp" #include "src/catalog/catalog_entry/duck_index_entry.cpp" diff --git a/src/duckdb/ub_src_catalog_default.cpp b/src/duckdb/ub_src_catalog_default.cpp index 7aeb3e3f0..ae7f84eee 100644 --- a/src/duckdb/ub_src_catalog_default.cpp +++ b/src/duckdb/ub_src_catalog_default.cpp @@ -1,3 +1,5 @@ +#include "src/catalog/default/default_coordinate_systems.cpp" + #include "src/catalog/default/default_functions.cpp" #include "src/catalog/default/default_generator.cpp" diff --git a/src/duckdb/ub_src_common.cpp b/src/duckdb/ub_src_common.cpp index f4f18e319..4e5ef02ec 100644 --- a/src/duckdb/ub_src_common.cpp +++ b/src/duckdb/ub_src_common.cpp @@ -24,6 +24,8 @@ #include "src/common/encryption_state.cpp" +#include "src/common/encryption_types.cpp" + #include "src/common/exception.cpp" #include "src/common/exception_format_value.cpp" diff --git a/src/duckdb/ub_src_common_types.cpp b/src/duckdb/ub_src_common_types.cpp index 5b4b933e1..57aa028c4 100644 --- a/src/duckdb/ub_src_common_types.cpp +++ b/src/duckdb/ub_src_common_types.cpp @@ -38,6 +38,8 @@ #include "src/common/types/timestamp.cpp" +#include "src/common/types/type_manager.cpp" + #include "src/common/types/time.cpp" #include "src/common/types/validity_mask.cpp" diff --git a/src/duckdb/ub_src_execution_operator_schema.cpp b/src/duckdb/ub_src_execution_operator_schema.cpp index 5f2940b11..ee2c8a274 100644 --- a/src/duckdb/ub_src_execution_operator_schema.cpp +++ b/src/duckdb/ub_src_execution_operator_schema.cpp @@ -20,5 +20,3 @@ #include "src/execution/operator/schema/physical_drop.cpp" -#include "src/execution/operator/schema/physical_create_art_index.cpp" - diff --git a/src/duckdb/ub_src_function_cast.cpp b/src/duckdb/ub_src_function_cast.cpp index 99f3378ca..3b71c2026 100644 --- a/src/duckdb/ub_src_function_cast.cpp +++ b/src/duckdb/ub_src_function_cast.cpp @@ -28,6 +28,8 @@ #include "src/function/cast/time_casts.cpp" +#include "src/function/cast/type_cast.cpp" + #include "src/function/cast/union_casts.cpp" #include "src/function/cast/uuid_casts.cpp" diff --git a/src/duckdb/ub_src_function_table_system.cpp b/src/duckdb/ub_src_function_table_system.cpp index 567670d0c..303f7436a 100644 --- a/src/duckdb/ub_src_function_table_system.cpp +++ b/src/duckdb/ub_src_function_table_system.cpp @@ -6,6 +6,8 @@ #include "src/function/table/system/duckdb_constraints.cpp" +#include "src/function/table/system/duckdb_coordinate_systems.cpp" + #include "src/function/table/system/duckdb_databases.cpp" #include "src/function/table/system/duckdb_dependencies.cpp" diff --git a/src/duckdb/ub_src_main.cpp b/src/duckdb/ub_src_main.cpp index b8bc22b97..5028119d6 100644 --- a/src/duckdb/ub_src_main.cpp +++ b/src/duckdb/ub_src_main.cpp @@ -36,6 +36,8 @@ #include "src/main/extension.cpp" +#include "src/main/extension_callback_manager.cpp" + #include "src/main/extension_install_info.cpp" #include "src/main/extension_manager.cpp" @@ -62,5 +64,7 @@ #include "src/main/stream_query_result.cpp" +#include "src/main/user_settings.cpp" + #include "src/main/valid_checker.cpp" diff --git a/src/duckdb/ub_src_main_settings.cpp b/src/duckdb/ub_src_main_settings.cpp index 6dbcd419e..c341379a7 100644 --- a/src/duckdb/ub_src_main_settings.cpp +++ b/src/duckdb/ub_src_main_settings.cpp @@ -2,3 +2,5 @@ #include "src/main/settings/autogenerated_settings.cpp" +#include "src/main/settings/settings.cpp" + diff --git a/src/duckdb/ub_src_parser_expression.cpp b/src/duckdb/ub_src_parser_expression.cpp index 1d9ba299b..d4bd7486e 100644 --- a/src/duckdb/ub_src_parser_expression.cpp +++ b/src/duckdb/ub_src_parser_expression.cpp @@ -32,5 +32,7 @@ #include "src/parser/expression/subquery_expression.cpp" +#include "src/parser/expression/type_expression.cpp" + #include "src/parser/expression/window_expression.cpp" diff --git a/src/duckdb/ub_src_parser_parsed_data.cpp b/src/duckdb/ub_src_parser_parsed_data.cpp index 37499ead1..535248c4f 100644 --- a/src/duckdb/ub_src_parser_parsed_data.cpp +++ b/src/duckdb/ub_src_parser_parsed_data.cpp @@ -24,6 +24,8 @@ #include "src/parser/parsed_data/create_collation_info.cpp" +#include "src/parser/parsed_data/create_coordinate_system_info.cpp" + #include "src/parser/parsed_data/create_copy_function_info.cpp" #include "src/parser/parsed_data/create_macro_info.cpp" diff --git a/src/duckdb/ub_src_planner_binder_expression.cpp b/src/duckdb/ub_src_planner_binder_expression.cpp index 86a595025..f02698c85 100644 --- a/src/duckdb/ub_src_planner_binder_expression.cpp +++ b/src/duckdb/ub_src_planner_binder_expression.cpp @@ -34,6 +34,8 @@ #include "src/planner/binder/expression/bind_subquery_expression.cpp" +#include "src/planner/binder/expression/bind_type_expression.cpp" + #include "src/planner/binder/expression/bind_unnest_expression.cpp" #include "src/planner/binder/expression/bind_window_expression.cpp" diff --git a/src/duckdb/ub_src_storage.cpp b/src/duckdb/ub_src_storage.cpp index 322cc1e18..ae703d262 100644 --- a/src/duckdb/ub_src_storage.cpp +++ b/src/duckdb/ub_src_storage.cpp @@ -46,6 +46,8 @@ #include "src/storage/single_file_block_manager.cpp" +#include "src/storage/storage_index.cpp" + #include "src/storage/storage_info.cpp" #include "src/storage/storage_lock.cpp" diff --git a/src/duckdb/ub_src_storage_table.cpp b/src/duckdb/ub_src_storage_table.cpp index 2a3777e94..e06c2d1cc 100644 --- a/src/duckdb/ub_src_storage_table.cpp +++ b/src/duckdb/ub_src_storage_table.cpp @@ -8,6 +8,8 @@ #include "src/storage/table/column_segment.cpp" +#include "src/storage/table/geo_column_data.cpp" + #include "src/storage/table/array_column_data.cpp" #include "src/storage/table/list_column_data.cpp"